BB10 (QNX 8 / ARMv7) port patches
Build/portability fixes for cross-compiling Qt 6.8.3 with GCC 9.3.0
against the BB10 QNX 8 sysroot:
corelib:
- qtypes.h: #define static_assert _Static_assert (QNX C11)
- qprocess_unix.cpp: #define O_DIRECTORY/O_PATH = 0
- qmath.h: qPow uses std::common_type to avoid pow ambiguity
- qmetaobject.cpp/_p.h: null-tolerant signal/inherits/cast/signalOffset
(THE BREAKTHROUGH that made Skywalker render — Qt6 widgets pass
null metaObject* in several lookup paths on BB10 QNX 8)
- qelfparser_p.cpp: backfill missing ELFOSABI_*/EM_*/SHT_*/PT_* defines
+ typedef Elf32_Nhdr Elf64_Nhdr (QNX has no 64-bit Elf_Nhdr)
- qlocale.cpp, qdatetime.cpp: explicit double casts for pow()
- qcoreapplication.cpp: misc QNX guard
gui:
- qpaintengineex.cpp: replace std::pow(v,2) with v*v
- qfontengine_ft.cpp: guard FT_IS_NAMED_INSTANCE / FT_Get_Var_Design_Coordinates
/ FT_Done_MM_Var on FreeType < 2.7.1
platforms/qnx (the BB10 QPA plugin):
- main.cpp, qqnxintegration.cpp: BB10 init tweaks
- qqnxscreen.h: _SCREEN_VERSION default + compat defines for missing
SCREEN_EVENT_MANAGER, SCREEN_OBJECT_TYPE_STREAM, *_PIXMAP/PARENT,
screen_manage_window stub
- qqnxscreeneventthread.cpp: MsgRegisterEvent/Unregister no-op fallback
- qqnxrasterwindow.cpp: BB10 raster window adjustments
- qqnxrasterbackingstore.cpp: full-window post in flush() to suppress
partial-update artifacts in the software backend
- qqnxscreeneventhandler.cpp/h: BB10 sticky-modifier emulation
(m_pendingModifiers — Q10 hw keyboard sends Shift/Ctrl/Alt as
separate KEY_DOWN events without a hold; apply to next key press)
bb10
parent
c07c2d5a52
commit
822d9e204c
|
|
@ -23,6 +23,11 @@
|
||||||
# include <type_traits>
|
# include <type_traits>
|
||||||
#else
|
#else
|
||||||
# include <assert.h>
|
# include <assert.h>
|
||||||
|
# if defined(__QNXNTO__) && !defined(static_assert)
|
||||||
|
/* QNX assert.h (BB10 / QNX 6.6) does not define the static_assert
|
||||||
|
* macro; provide it via the C11 _Static_assert keyword. */
|
||||||
|
# define static_assert _Static_assert
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,13 @@
|
||||||
|
|
||||||
#ifdef Q_OS_QNX
|
#ifdef Q_OS_QNX
|
||||||
# include <sys/neutrino.h>
|
# include <sys/neutrino.h>
|
||||||
|
/* O_DIRECTORY and O_PATH are Linux-specific; not defined in QNX 6.6. */
|
||||||
|
# ifndef O_DIRECTORY
|
||||||
|
# define O_DIRECTORY 0
|
||||||
|
# endif
|
||||||
|
# ifndef O_PATH
|
||||||
|
# define O_PATH 0
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
# include <locale.h>
|
# include <locale.h>
|
||||||
# ifndef Q_OS_INTEGRITY
|
# if !defined(Q_OS_INTEGRITY) && !defined(Q_OS_QNX) // QNX/BB10 has no langinfo.h
|
||||||
# include <langinfo.h>
|
# include <langinfo.h>
|
||||||
# endif
|
# endif
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
|
|
|
||||||
|
|
@ -179,8 +179,11 @@ template <typename T> auto qExp(T v)
|
||||||
|
|
||||||
template <typename T1, typename T2> auto qPow(T1 x, T2 y)
|
template <typename T1, typename T2> auto qPow(T1 x, T2 y)
|
||||||
{
|
{
|
||||||
using std::pow;
|
// Cast both args to their common type to avoid ambiguous overload between
|
||||||
return pow(x, y);
|
// QNX math.h _TGEN_RC2 template and GCC <cmath> template for mixed types
|
||||||
|
// (e.g. qPow(float, double) would be ambiguous without this).
|
||||||
|
typedef typename std::common_type<T1, T2>::type CT;
|
||||||
|
return std::pow(static_cast<CT>(x), static_cast<CT>(y));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use template variables (e.g. Qt::pi<type>) for these once we have C++14 support:
|
// TODO: use template variables (e.g. Qt::pi<type>) for these once we have C++14 support:
|
||||||
|
|
|
||||||
|
|
@ -371,6 +371,7 @@ const char *QMetaObject::className() const
|
||||||
bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept
|
bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept
|
||||||
{
|
{
|
||||||
const QMetaObject *m = this;
|
const QMetaObject *m = this;
|
||||||
|
if (!m) return false; // BB10: tolerate null this
|
||||||
do {
|
do {
|
||||||
if (metaObject == m)
|
if (metaObject == m)
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -394,7 +395,12 @@ bool QMetaObject::inherits(const QMetaObject *metaObject) const noexcept
|
||||||
*/
|
*/
|
||||||
const QObject *QMetaObject::cast(const QObject *obj) const
|
const QObject *QMetaObject::cast(const QObject *obj) const
|
||||||
{
|
{
|
||||||
return (obj && obj->metaObject()->inherits(this)) ? obj : nullptr;
|
// BB10: tolerate null this and null obj->metaObject()
|
||||||
|
if (!this) return nullptr;
|
||||||
|
if (!obj) return nullptr;
|
||||||
|
const QMetaObject *m = obj->metaObject();
|
||||||
|
if (!m) return nullptr;
|
||||||
|
return m->inherits(this) ? obj : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef QT_NO_TRANSLATION
|
#ifndef QT_NO_TRANSLATION
|
||||||
|
|
@ -970,7 +976,9 @@ QMetaMethod QMetaObjectPrivate::signal(const QMetaObject *m, int signal_index)
|
||||||
if (signal_index < 0)
|
if (signal_index < 0)
|
||||||
return QMetaMethod();
|
return QMetaMethod();
|
||||||
|
|
||||||
Q_ASSERT(m != nullptr);
|
// BB10: tolerate null QMetaObject instead of SIGSEGV
|
||||||
|
if (!m)
|
||||||
|
return QMetaMethod();
|
||||||
int i = signal_index;
|
int i = signal_index;
|
||||||
i -= signalOffset(m);
|
i -= signalOffset(m);
|
||||||
if (i < 0 && m->d.superdata)
|
if (i < 0 && m->d.superdata)
|
||||||
|
|
|
||||||
|
|
@ -216,7 +216,7 @@ struct QMetaObjectPrivate
|
||||||
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
|
Q_CORE_EXPORT static QMetaMethod signal(const QMetaObject *m, int signal_index);
|
||||||
static inline int signalOffset(const QMetaObject *m)
|
static inline int signalOffset(const QMetaObject *m)
|
||||||
{
|
{
|
||||||
Q_ASSERT(m != nullptr);
|
if (!m) return 0; // BB10: tolerate null instead of crashing
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (m = m->d.superdata; m; m = m->d.superdata)
|
for (m = m->d.superdata; m; m = m->d.superdata)
|
||||||
offset += reinterpret_cast<const QMetaObjectPrivate *>(m->d.data)->signalCount;
|
offset += reinterpret_cast<const QMetaObjectPrivate *>(m->d.data)->signalCount;
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,54 @@
|
||||||
# error "Need ELF header to parse plugins."
|
# error "Need ELF header to parse plugins."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef Q_OS_QNX
|
||||||
|
/* QNX sys/elf.h (BB10 / QNX 6.6) uses non-standard enum values for ELFOSABI_*
|
||||||
|
* and omits many EM_*, SHT_*, SHF_*, and PT_* constants defined in the standard
|
||||||
|
* System V ABI. Redefine OSABI values as macros (which shadow the enum members)
|
||||||
|
* and add the missing constants so this file compiles without errors. */
|
||||||
|
|
||||||
|
/* --- OSABI: override with standard values (QNX enum order is non-standard) --- */
|
||||||
|
# define ELFOSABI_SYSV 0
|
||||||
|
# define ELFOSABI_NONE 0
|
||||||
|
# define ELFOSABI_HPUX 1
|
||||||
|
# define ELFOSABI_NETBSD 2
|
||||||
|
# define ELFOSABI_LINUX 3
|
||||||
|
# define ELFOSABI_SOLARIS 6
|
||||||
|
# define ELFOSABI_AIX 7
|
||||||
|
# define ELFOSABI_IRIX 8
|
||||||
|
# define ELFOSABI_FREEBSD 9
|
||||||
|
# define ELFOSABI_OPENBSD 12
|
||||||
|
|
||||||
|
/* --- EM_* machine types missing from QNX sys/elf.h --- */
|
||||||
|
# define EM_68K 4 /* Motorola 68000 */
|
||||||
|
# define EM_PARISC 15 /* HP PA-RISC (QNX has EM_PA_RISC) */
|
||||||
|
# define EM_PPC64 21 /* PowerPC 64-bit */
|
||||||
|
# define EM_S390 22 /* IBM System/390 */
|
||||||
|
# define EM_IA_64 50 /* Intel IA-64 */
|
||||||
|
# define EM_X86_64 62 /* AMD/Intel x86-64 */
|
||||||
|
# define EM_SPARCV9 43 /* SPARC V9 */
|
||||||
|
# define EM_ALPHA 0x9026 /* DEC Alpha (unofficial but widely used) */
|
||||||
|
# define EM_AARCH64 183 /* ARM AArch64 */
|
||||||
|
# define EM_BLACKFIN 106 /* Analog Devices Blackfin */
|
||||||
|
# define EM_RISCV 243 /* RISC-V */
|
||||||
|
# define EM_LOONGARCH 258 /* LoongArch */
|
||||||
|
|
||||||
|
/* --- SHT_* section types missing from QNX sys/elf.h --- */
|
||||||
|
# define SHT_INIT_ARRAY 14 /* Array of constructors */
|
||||||
|
# define SHT_FINI_ARRAY 15 /* Array of destructors */
|
||||||
|
|
||||||
|
/* --- SHF_* section flags missing from QNX sys/elf.h --- */
|
||||||
|
# define SHF_STRINGS 0x20 /* Contains NUL-terminated strings */
|
||||||
|
# define SHF_TLS 0x400 /* Section holds thread-local storage */
|
||||||
|
|
||||||
|
/* --- PT_* program header types missing from QNX sys/elf.h --- */
|
||||||
|
# define PT_TLS 7 /* Thread-local storage segment */
|
||||||
|
# define PT_GNU_PROPERTY 0x6474e553u /* GNU property notes */
|
||||||
|
|
||||||
|
/* --- Elf64_Nhdr absent in QNX; alias to Elf32_Nhdr (never used on ARM32) --- */
|
||||||
|
typedef Elf32_Nhdr Elf64_Nhdr;
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
|
||||||
|
|
@ -4798,14 +4798,14 @@ QString QLocale::formattedDataSize(qint64 bytes, int precision, DataSizeFormats
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
power = 0;
|
power = 0;
|
||||||
} else if (format & DataSizeBase1000) {
|
} else if (format & DataSizeBase1000) {
|
||||||
power = int(std::log10(QtPrivate::qUnsignedAbs(bytes)) / 3);
|
power = int(std::log10(double(QtPrivate::qUnsignedAbs(bytes))) / 3);
|
||||||
} else { // Compute log2(bytes) / 10:
|
} else { // Compute log2(bytes) / 10:
|
||||||
power = int((63 - qCountLeadingZeroBits(QtPrivate::qUnsignedAbs(bytes))) / 10);
|
power = int((63 - qCountLeadingZeroBits(QtPrivate::qUnsignedAbs(bytes))) / 10);
|
||||||
base = 1024;
|
base = 1024;
|
||||||
}
|
}
|
||||||
// Only go to doubles if we'll be using a quantifier:
|
// Only go to doubles if we'll be using a quantifier:
|
||||||
const QString number = power
|
const QString number = power
|
||||||
? toString(bytes / std::pow(double(base), power), 'f', qMin(precision, 3 * power))
|
? toString(bytes / std::pow(double(base), double(power)), 'f', qMin(precision, 3 * power))
|
||||||
: toString(bytes);
|
: toString(bytes);
|
||||||
|
|
||||||
// We don't support sizes in units larger than exbibytes because
|
// We don't support sizes in units larger than exbibytes because
|
||||||
|
|
|
||||||
|
|
@ -2475,7 +2475,7 @@ static QTime fromIsoTimeString(QStringView string, Qt::DateFormat format, bool *
|
||||||
if (tail.isEmpty() ? dot != -1 || comma != -1 : !frac.ok())
|
if (tail.isEmpty() ? dot != -1 || comma != -1 : !frac.ok())
|
||||||
return QTime();
|
return QTime();
|
||||||
Q_ASSERT(frac.ok() ^ tail.isEmpty());
|
Q_ASSERT(frac.ok() ^ tail.isEmpty());
|
||||||
double fraction = frac.ok() ? frac.result * std::pow(0.1, tail.size()) : 0.0;
|
double fraction = frac.ok() ? frac.result * std::pow(0.1, (double)tail.size()) : 0.0;
|
||||||
|
|
||||||
const qsizetype size = string.size();
|
const qsizetype size = string.size();
|
||||||
if (size < 2 || size > 8)
|
if (size < 2 || size > 8)
|
||||||
|
|
|
||||||
|
|
@ -1085,11 +1085,14 @@ bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTran
|
||||||
if (fontEngine->glyphFormat == QFontEngine::Format_ARGB)
|
if (fontEngine->glyphFormat == QFontEngine::Format_ARGB)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
static const int maxCachedGlyphSizeSquared = std::pow([]{
|
static const int maxCachedGlyphSizeSquared = []{
|
||||||
if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE"))
|
const int v = []{ /* std::pow(int,int) is ambiguous on QNX; use v*v */
|
||||||
return env;
|
if (int env = qEnvironmentVariableIntValue("QT_MAX_CACHED_GLYPH_SIZE"))
|
||||||
return QT_MAX_CACHED_GLYPH_SIZE;
|
return env;
|
||||||
}(), 2);
|
return QT_MAX_CACHED_GLYPH_SIZE;
|
||||||
|
}();
|
||||||
|
return v * v;
|
||||||
|
}();
|
||||||
|
|
||||||
qreal pixelSize = fontEngine->fontDef.pixelSize;
|
qreal pixelSize = fontEngine->fontDef.pixelSize;
|
||||||
return (pixelSize * pixelSize * qAbs(m.determinant())) <= maxCachedGlyphSizeSquared;
|
return (pixelSize * pixelSize * qAbs(m.determinant())) <= maxCachedGlyphSizeSquared;
|
||||||
|
|
|
||||||
|
|
@ -283,12 +283,14 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
|
||||||
#endif
|
#endif
|
||||||
newFreetype->face = face;
|
newFreetype->face = face;
|
||||||
newFreetype->mm_var = nullptr;
|
newFreetype->mm_var = nullptr;
|
||||||
|
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20700
|
||||||
if (FT_IS_NAMED_INSTANCE(newFreetype->face)) {
|
if (FT_IS_NAMED_INSTANCE(newFreetype->face)) {
|
||||||
FT_Error ftresult;
|
FT_Error ftresult;
|
||||||
ftresult = FT_Get_MM_Var(face, &newFreetype->mm_var);
|
ftresult = FT_Get_MM_Var(face, &newFreetype->mm_var);
|
||||||
if (ftresult != FT_Err_Ok)
|
if (ftresult != FT_Err_Ok)
|
||||||
newFreetype->mm_var = nullptr;
|
newFreetype->mm_var = nullptr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
newFreetype->ref.storeRelaxed(1);
|
newFreetype->ref.storeRelaxed(1);
|
||||||
newFreetype->xsize = 0;
|
newFreetype->xsize = 0;
|
||||||
|
|
@ -328,6 +330,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
|
||||||
|
|
||||||
FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
|
FT_Set_Charmap(newFreetype->face, newFreetype->unicode_map);
|
||||||
|
|
||||||
|
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20701
|
||||||
if (!face_id.variableAxes.isEmpty()) {
|
if (!face_id.variableAxes.isEmpty()) {
|
||||||
FT_MM_Var *var = nullptr;
|
FT_MM_Var *var = nullptr;
|
||||||
FT_Get_MM_Var(newFreetype->face, &var);
|
FT_Get_MM_Var(newFreetype->face, &var);
|
||||||
|
|
@ -345,6 +348,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
|
||||||
FT_Done_MM_Var(qt_getFreetype(), var);
|
FT_Done_MM_Var(qt_getFreetype(), var);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_TRY {
|
QT_TRY {
|
||||||
freetypeData->faces.insert(face_id, newFreetype.get());
|
freetypeData->faces.insert(face_id, newFreetype.get());
|
||||||
|
|
@ -362,8 +366,10 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
|
||||||
void QFreetypeFace::cleanup()
|
void QFreetypeFace::cleanup()
|
||||||
{
|
{
|
||||||
hbFace.reset();
|
hbFace.reset();
|
||||||
|
#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 20701
|
||||||
if (mm_var && face && face->glyph)
|
if (mm_var && face && face->glyph)
|
||||||
FT_Done_MM_Var(face->glyph->library, mm_var);
|
FT_Done_MM_Var(face->glyph->library, mm_var);
|
||||||
|
#endif
|
||||||
mm_var = nullptr;
|
mm_var = nullptr;
|
||||||
FT_Done_Face(face);
|
FT_Done_Face(face);
|
||||||
face = nullptr;
|
face = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "qqnxintegration.h"
|
#include "qqnxintegration.h"
|
||||||
#include "qqnxlgmon.h"
|
#include "qqnxlgmon.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
|
@ -11,11 +12,18 @@ using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList)
|
QPlatformIntegration *QQnxIntegrationPlugin::create(const QString& system, const QStringList& paramList)
|
||||||
{
|
{
|
||||||
|
fprintf(stderr, "QNX-PLUGIN: create(system=%s) called\n", system.toLocal8Bit().constData());
|
||||||
|
fflush(stderr);
|
||||||
if (!system.compare("qnx"_L1, Qt::CaseInsensitive)) {
|
if (!system.compare("qnx"_L1, Qt::CaseInsensitive)) {
|
||||||
|
fprintf(stderr, "QNX-PLUGIN: qqnxLgmonInit()...\n"); fflush(stderr);
|
||||||
qqnxLgmonInit();
|
qqnxLgmonInit();
|
||||||
return new QQnxIntegration(paramList);
|
fprintf(stderr, "QNX-PLUGIN: new QQnxIntegration()...\n"); fflush(stderr);
|
||||||
|
QPlatformIntegration *r = new QQnxIntegration(paramList);
|
||||||
|
fprintf(stderr, "QNX-PLUGIN: QQnxIntegration constructed = %p\n", r); fflush(stderr);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "QNX-PLUGIN: system mismatch, returning 0\n"); fflush(stderr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -148,19 +148,28 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList)
|
||||||
qCDebug(lcQpaQnx) << Q_FUNC_INFO;
|
qCDebug(lcQpaQnx) << Q_FUNC_INFO;
|
||||||
|
|
||||||
// Open connection to QNX composition manager
|
// Open connection to QNX composition manager
|
||||||
|
fprintf(stderr, "QNX: screen_create_context(caps=0x%x) ...\n", getContextCapabilities(paramList));
|
||||||
|
fflush(stderr);
|
||||||
if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
|
if (screen_create_context(&m_screenContext, getContextCapabilities(paramList))) {
|
||||||
|
fprintf(stderr, "QNX: screen_create_context FAILED: %s (%d)\n", strerror(errno), errno);
|
||||||
|
fflush(stderr);
|
||||||
qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)",
|
qFatal("%s - Screen: Failed to create screen context - Error: %s (%i)",
|
||||||
Q_FUNC_INFO, strerror(errno), errno);
|
Q_FUNC_INFO, strerror(errno), errno);
|
||||||
}
|
}
|
||||||
|
fprintf(stderr, "QNX: screen_create_context OK\n");
|
||||||
|
fflush(stderr);
|
||||||
screen_get_context_property_cv(m_screenContext,
|
screen_get_context_property_cv(m_screenContext,
|
||||||
SCREEN_PROPERTY_ID,
|
SCREEN_PROPERTY_ID,
|
||||||
m_screenContextId.size(),
|
m_screenContextId.size(),
|
||||||
m_screenContextId.data());
|
m_screenContextId.data());
|
||||||
m_screenContextId.resize(strlen(m_screenContextId.constData()));
|
m_screenContextId.resize(strlen(m_screenContextId.constData()));
|
||||||
|
fprintf(stderr, "QNX: context id: %s\n", m_screenContextId.constData());
|
||||||
|
fflush(stderr);
|
||||||
|
|
||||||
#if QT_CONFIG(qqnx_pps)
|
#if QT_CONFIG(qqnx_pps)
|
||||||
// Create/start navigator event notifier
|
// Create/start navigator event notifier
|
||||||
m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler);
|
m_navigatorEventNotifier = new QQnxNavigatorEventNotifier(m_navigatorEventHandler);
|
||||||
|
fprintf(stderr, "QNX: navigatorEventNotifier created\n"); fflush(stderr);
|
||||||
|
|
||||||
// delay invocation of start() to the time the event loop is up and running
|
// delay invocation of start() to the time the event loop is up and running
|
||||||
// needed to have the QThread internals of the main thread properly initialized
|
// needed to have the QThread internals of the main thread properly initialized
|
||||||
|
|
@ -168,20 +177,26 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if QT_CONFIG(opengl)
|
#if QT_CONFIG(opengl)
|
||||||
|
fprintf(stderr, "QNX: createEglDisplay...\n"); fflush(stderr);
|
||||||
createEglDisplay();
|
createEglDisplay();
|
||||||
|
fprintf(stderr, "QNX: createEglDisplay done\n"); fflush(stderr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Create/start event thread
|
// Create/start event thread
|
||||||
|
fprintf(stderr, "QNX: creating screenEventThread...\n"); fflush(stderr);
|
||||||
m_screenEventThread = new QQnxScreenEventThread(m_screenContext);
|
m_screenEventThread = new QQnxScreenEventThread(m_screenContext);
|
||||||
m_screenEventHandler->setScreenEventThread(m_screenEventThread);
|
m_screenEventHandler->setScreenEventThread(m_screenEventThread);
|
||||||
m_screenEventThread->start();
|
m_screenEventThread->start();
|
||||||
|
fprintf(stderr, "QNX: screenEventThread started\n"); fflush(stderr);
|
||||||
|
|
||||||
m_qpaInputContext = QPlatformInputContextFactory::create();
|
m_qpaInputContext = QPlatformInputContextFactory::create();
|
||||||
|
fprintf(stderr, "QNX: inputContext=%p\n", m_qpaInputContext); fflush(stderr);
|
||||||
|
|
||||||
#if QT_CONFIG(qqnx_pps)
|
#if QT_CONFIG(qqnx_pps)
|
||||||
if (!m_qpaInputContext) {
|
if (!m_qpaInputContext) {
|
||||||
// Create/start the keyboard class.
|
// Create/start the keyboard class.
|
||||||
m_virtualKeyboard = new QQnxVirtualKeyboardPps();
|
m_virtualKeyboard = new QQnxVirtualKeyboardPps();
|
||||||
|
fprintf(stderr, "QNX: virtualKeyboard created\n"); fflush(stderr);
|
||||||
|
|
||||||
// delay invocation of start() to the time the event loop is up and running
|
// delay invocation of start() to the time the event loop is up and running
|
||||||
// needed to have the QThread internals of the main thread properly initialized
|
// needed to have the QThread internals of the main thread properly initialized
|
||||||
|
|
@ -191,9 +206,12 @@ QQnxIntegration::QQnxIntegration(const QStringList ¶mList)
|
||||||
|
|
||||||
#if QT_CONFIG(qqnx_pps)
|
#if QT_CONFIG(qqnx_pps)
|
||||||
m_navigator = new QQnxNavigatorPps();
|
m_navigator = new QQnxNavigatorPps();
|
||||||
|
fprintf(stderr, "QNX: navigator created\n"); fflush(stderr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
fprintf(stderr, "QNX: createDisplays...\n"); fflush(stderr);
|
||||||
createDisplays();
|
createDisplays();
|
||||||
|
fprintf(stderr, "QNX: createDisplays done\n"); fflush(stderr);
|
||||||
|
|
||||||
if (m_virtualKeyboard) {
|
if (m_virtualKeyboard) {
|
||||||
// TODO check if we need to do this for all screens or only the primary one
|
// TODO check if we need to do this for all screens or only the primary one
|
||||||
|
|
@ -731,12 +749,24 @@ void QQnxIntegration::createEglDisplay()
|
||||||
|
|
||||||
// Initialize connection to EGL
|
// Initialize connection to EGL
|
||||||
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||||
if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY))
|
if (Q_UNLIKELY(m_eglDisplay == EGL_NO_DISPLAY)) {
|
||||||
qFatal("QQnxiIntegration: failed to obtain EGL display: %x", eglGetError());
|
// BB10 sandbox: EGL may not be available without a screen window yet.
|
||||||
|
// Fall back to raster/software rendering instead of aborting.
|
||||||
|
fprintf(stderr, "QNX: eglGetDisplay(EGL_DEFAULT_DISPLAY) failed (err=0x%x) — raster fallback\n",
|
||||||
|
eglGetError());
|
||||||
|
fflush(stderr);
|
||||||
|
m_eglDisplay = EGL_NO_DISPLAY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
EGLBoolean eglResult = eglInitialize(m_eglDisplay, 0, 0);
|
EGLBoolean eglResult = eglInitialize(m_eglDisplay, 0, 0);
|
||||||
if (Q_UNLIKELY(eglResult != EGL_TRUE))
|
if (Q_UNLIKELY(eglResult != EGL_TRUE)) {
|
||||||
qFatal("QQnxIntegration: failed to initialize EGL display, err=%d", eglGetError());
|
fprintf(stderr, "QNX: eglInitialize failed (err=0x%x) — raster fallback\n",
|
||||||
|
eglGetError());
|
||||||
|
fflush(stderr);
|
||||||
|
m_eglDisplay = EGL_NO_DISPLAY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QQnxIntegration::destroyEglDisplay()
|
void QQnxIntegration::destroyEglDisplay()
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,15 @@ void QQnxRasterBackingStore::flush(QWindow *window, const QRegion ®ion, const
|
||||||
auto *targetWindow = window
|
auto *targetWindow = window
|
||||||
? static_cast<QQnxRasterWindow *>(window->handle()) : platformWindow();
|
? static_cast<QQnxRasterWindow *>(window->handle()) : platformWindow();
|
||||||
|
|
||||||
if (targetWindow)
|
if (targetWindow) {
|
||||||
targetWindow->post(region); // update the display with newly rendered content
|
// BB10 software-backend QtQuick: incremental dirty regions sometimes
|
||||||
|
// miss areas that were animated/scrolled (e.g. SwipeView contents),
|
||||||
|
// leaving stale pixels visible until a full repaint. Post the entire
|
||||||
|
// window each flush to avoid that — costs a bit more bandwidth, but
|
||||||
|
// eliminates the "wave/swirl" partial-update artifacts.
|
||||||
|
QRegion full = QRect(QPoint(0, 0), targetWindow->geometry().size());
|
||||||
|
targetWindow->post(full);
|
||||||
|
}
|
||||||
|
|
||||||
m_needsPosting = false;
|
m_needsPosting = false;
|
||||||
m_scrolled = false;
|
m_scrolled = false;
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,16 @@ void QQnxRasterWindow::post(const QRegion &dirty)
|
||||||
screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0),
|
screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0),
|
||||||
"Failed to post window");
|
"Failed to post window");
|
||||||
#else
|
#else
|
||||||
// Update the display with contents of render buffer
|
// Update the display with contents of render buffer.
|
||||||
Q_SCREEN_CHECKERROR(
|
// BB10 (QNX 6.6) screen_post_window() ignores numrects=0/NULL and posts
|
||||||
screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 0, NULL, 0),
|
// nothing; pass the explicit bounding rect so it actually composites.
|
||||||
"Failed to post window");
|
{
|
||||||
|
QRect rect = dirty.boundingRect();
|
||||||
|
int dirtyRect[4] = { rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height() };
|
||||||
|
Q_SCREEN_CHECKERROR(
|
||||||
|
screen_post_window(nativeHandle(), currentBuffer.nativeBuffer(), 1, dirtyRect, 0),
|
||||||
|
"Failed to post window");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Advance to next nender buffer
|
// Advance to next nender buffer
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,10 @@
|
||||||
|
|
||||||
#if !defined(_SCREEN_VERSION)
|
#if !defined(_SCREEN_VERSION)
|
||||||
#define _SCREEN_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
|
#define _SCREEN_MAKE_VERSION(major, minor, patch) (((major) * 10000) + ((minor) * 100) + (patch))
|
||||||
#define _SCREEN_VERSION _SCREEN_MAKE_VERSION(0, 0, 0)
|
/* QNX 8.x / BB10 screen.h doesn't define _SCREEN_VERSION but already uses the
|
||||||
|
* 1.x property names (SCREEN_PROPERTY_FLAGS, SCREEN_PROPERTY_FOCUS, etc.).
|
||||||
|
* Default to 1.0.0 so the old-name alias block below is skipped. */
|
||||||
|
#define _SCREEN_VERSION _SCREEN_MAKE_VERSION(1, 0, 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// For pre-1.0.0 screen, map some screen property names to the old
|
// For pre-1.0.0 screen, map some screen property names to the old
|
||||||
|
|
@ -28,6 +31,40 @@ const int SCREEN_PROPERTY_SCAN = SCREEN_PROPERTY_KEY_SCAN;
|
||||||
const int SCREEN_PROPERTY_SYM = SCREEN_PROPERTY_KEY_SYM;
|
const int SCREEN_PROPERTY_SYM = SCREEN_PROPERTY_KEY_SYM;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// BB10 / QNX 8 sysroot (screen API ~1.x) lacks some symbols added in QNX
|
||||||
|
// Screen 2.x. Define placeholders so the QNX QPA plugin compiles; these
|
||||||
|
// events/properties will simply never appear on BB10 hardware.
|
||||||
|
#ifndef SCREEN_EVENT_MANAGER
|
||||||
|
# define SCREEN_EVENT_MANAGER 0x7ffe01 /* never fired on BB10 */
|
||||||
|
#endif
|
||||||
|
#ifndef SCREEN_OBJECT_TYPE_STREAM
|
||||||
|
# define SCREEN_OBJECT_TYPE_STREAM 0x7ffe02
|
||||||
|
#endif
|
||||||
|
#ifndef SCREEN_PROPERTY_SUBTYPE
|
||||||
|
# define SCREEN_PROPERTY_SUBTYPE 0x7ffe03
|
||||||
|
#endif
|
||||||
|
// SCREEN_PROPERTY_PIXMAP (singular) is the per-event pixmap handle property.
|
||||||
|
// BB10 uses SCREEN_PROPERTY_PIXMAPS (plural, window's pixmap list); use it
|
||||||
|
// as a best-effort stand-in for pixmap close-event handling.
|
||||||
|
#ifndef SCREEN_PROPERTY_PIXMAP
|
||||||
|
# define SCREEN_PROPERTY_PIXMAP SCREEN_PROPERTY_PIXMAPS
|
||||||
|
#endif
|
||||||
|
// SCREEN_PROPERTY_PARENT — parent group name property; alias to GROUP on BB10.
|
||||||
|
#ifndef SCREEN_PROPERTY_PARENT
|
||||||
|
# define SCREEN_PROPERTY_PARENT SCREEN_PROPERTY_GROUP
|
||||||
|
#endif
|
||||||
|
// screen_manage_window — window manager handshake, added in QNX 7.x.
|
||||||
|
// On BB10 there is no formal window manager; provide a no-op stub.
|
||||||
|
#if !defined(screen_manage_window)
|
||||||
|
# ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
# endif
|
||||||
|
static inline int screen_manage_window(screen_window_t, const char *) { return 0; }
|
||||||
|
# ifdef __cplusplus
|
||||||
|
}
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen);
|
Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "qqnxglobal.h"
|
#include "qqnxglobal.h"
|
||||||
|
|
||||||
#include "qqnxscreeneventhandler.h"
|
#include "qqnxscreeneventhandler.h"
|
||||||
|
#include <sys/keycodes.h>
|
||||||
#include "qqnxscreeneventthread.h"
|
#include "qqnxscreeneventthread.h"
|
||||||
#include "qqnxintegration.h"
|
#include "qqnxintegration.h"
|
||||||
#include "qqnxkeytranslator.h"
|
#include "qqnxkeytranslator.h"
|
||||||
|
|
@ -306,6 +307,44 @@ void QQnxScreenEventHandler::handleKeyboardEvent(screen_event_t event)
|
||||||
int sequenceId = 0;
|
int sequenceId = 0;
|
||||||
bool inject = true;
|
bool inject = true;
|
||||||
|
|
||||||
|
// BB10 sticky-modifier emulation: on Q10 the hardware keyboard sends a
|
||||||
|
// separate KEY_DOWN event for the Shift/Alt key, then releases it, then
|
||||||
|
// sends the next char with modifiers=0. Cascades apps see the shifted
|
||||||
|
// char because BlackBerry's input layer remembers the last pressed
|
||||||
|
// modifier. We do the same here: if the event IS a modifier press/
|
||||||
|
// release, remember/clear it; if it's a real key, OR-in the pending
|
||||||
|
// modifier and consume it.
|
||||||
|
{
|
||||||
|
bool isModifierKey = false;
|
||||||
|
int modifierBit = 0;
|
||||||
|
switch (sym) {
|
||||||
|
case KEYCODE_LEFT_SHIFT:
|
||||||
|
case KEYCODE_RIGHT_SHIFT:
|
||||||
|
isModifierKey = true; modifierBit = KEYMOD_SHIFT; break;
|
||||||
|
case KEYCODE_LEFT_CTRL:
|
||||||
|
case KEYCODE_RIGHT_CTRL:
|
||||||
|
isModifierKey = true; modifierBit = KEYMOD_CTRL; break;
|
||||||
|
case KEYCODE_LEFT_ALT:
|
||||||
|
case KEYCODE_RIGHT_ALT:
|
||||||
|
isModifierKey = true; modifierBit = KEYMOD_ALT; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
if (isModifierKey) {
|
||||||
|
if (flags & KEY_DOWN)
|
||||||
|
m_pendingModifiers |= modifierBit;
|
||||||
|
// Don't clear on KEY_UP — keep until the next non-modifier key
|
||||||
|
// is processed, that's the "sticky" behaviour BB10 users expect.
|
||||||
|
} else if (flags & KEY_DOWN) {
|
||||||
|
// Non-modifier key going down: merge sticky modifiers, then clear.
|
||||||
|
if (m_pendingModifiers) {
|
||||||
|
modifiers |= m_pendingModifiers;
|
||||||
|
// Re-derive the shifted symbol if Shift is now active and we
|
||||||
|
// received a base-cap from the keyboard with no SYM_VALID.
|
||||||
|
m_pendingModifiers = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) {
|
Q_FOREACH (QQnxScreenEventFilter *filter, m_eventFilters) {
|
||||||
if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) {
|
if (filter->handleKeyboardEvent(flags, sym, modifiers, scan, cap, sequenceId)) {
|
||||||
inject = false;
|
inject = false;
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ private:
|
||||||
QPoint m_lastLocalMousePoint;
|
QPoint m_lastLocalMousePoint;
|
||||||
Qt::MouseButtons m_lastButtonState;
|
Qt::MouseButtons m_lastButtonState;
|
||||||
screen_window_t m_lastMouseWindow;
|
screen_window_t m_lastMouseWindow;
|
||||||
|
// BB10 sticky-modifier support — Q10 hardware keyboard sends shift/alt as
|
||||||
|
// separate events without holding; remember them for the next key.
|
||||||
|
int m_pendingModifiers = 0;
|
||||||
QPointingDevice *m_touchDevice;
|
QPointingDevice *m_touchDevice;
|
||||||
QPointingDevice *m_mouseDevice;
|
QPointingDevice *m_mouseDevice;
|
||||||
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
|
QWindowSystemInterface::TouchPoint m_touchPoints[MaximumTouchPoints];
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,24 @@ static const int c_quitCode = _PULSE_CODE_MINAVAIL + 2;
|
||||||
#if !defined(screen_register_event)
|
#if !defined(screen_register_event)
|
||||||
int screen_register_event(screen_context_t, struct sigevent *event)
|
int screen_register_event(screen_context_t, struct sigevent *event)
|
||||||
{
|
{
|
||||||
|
#if defined(MsgRegisterEvent)
|
||||||
return MsgRegisterEvent(event, -1);
|
return MsgRegisterEvent(event, -1);
|
||||||
|
#else
|
||||||
|
/* BB10 / QNX 8: event registration is performed via screen_notify;
|
||||||
|
* this function is a no-op here. */
|
||||||
|
(void)event;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int screen_unregister_event(struct sigevent *event)
|
int screen_unregister_event(struct sigevent *event)
|
||||||
{
|
{
|
||||||
|
#if defined(MsgUnregisterEvent)
|
||||||
return MsgUnregisterEvent(event);
|
return MsgUnregisterEvent(event);
|
||||||
|
#else
|
||||||
|
(void)event;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue