summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/generic/evdevtouch/README13
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp3
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.cpp108
-rw-r--r--src/plugins/platforms/android/qandroidinputcontext.h3
-rw-r--r--src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp19
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.cpp18
-rw-r--r--src/plugins/platforms/android/qandroidplatformfontdatabase.h3
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.cpp43
-rw-r--r--src/plugins/platforms/android/qandroidplatformintegration.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.cpp18
-rw-r--r--src/plugins/platforms/android/qandroidplatformopenglcontext.h2
-rw-r--r--src/plugins/platforms/android/qandroidplatformrasterwindow.cpp4
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.cpp13
-rw-r--r--src/plugins/platforms/android/qandroidplatformscreen.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm18
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm34
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm8
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm53
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.mm8
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp4
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_stub.cpp11
-rw-r--r--src/plugins/platforms/ios/qioscontext.h2
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm69
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm64
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h1
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm7
-rw-r--r--src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp16
-rw-r--r--src/plugins/platforms/qnx/qqnxfilepicker.cpp8
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp5
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp8
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp3
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp29
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h10
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp10
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h3
-rw-r--r--src/plugins/platforms/winrt/qwinrtfontdatabase.cpp331
-rw-r--r--src/plugins/platforms/winrt/qwinrtfontdatabase.h3
-rw-r--r--src/plugins/platforms/winrt/qwinrtintegration.cpp2
-rw-r--r--src/plugins/platforms/winrt/winrt.pro9
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp69
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp285
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.h36
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp10
-rw-r--r--src/plugins/platforms/xcb/xcb-plugin.pro8
51 files changed, 891 insertions, 525 deletions
diff --git a/src/plugins/generic/evdevtouch/README b/src/plugins/generic/evdevtouch/README
index 833b511fd8..e5c9aff0af 100644
--- a/src/plugins/generic/evdevtouch/README
+++ b/src/plugins/generic/evdevtouch/README
@@ -1,20 +1,17 @@
Generic plug-in for evdev multiple touch (ABS_MT) events.
Supports protocol type A & B.
Type B is supported both directly and via libmtdev.
-Single-touch devices reporting ABS_X and Y only are not supported
-by this plugin. Use tslib or evdevmouse instead.
-
The protocol type will be detected automatically.
libmtdev is automatically detected based on library availability. To disable it,
pass -no-mtdev to configure.
-Tested with the following kernel drivers:
- bcm5974 (type A)
- hid_magicmouse (type A with ABS_MT_TRACKING_ID) (type B over libmtdev)
- wacom (type B)
+Single-touch devices reporting ABS_X and Y are supported too. Keep in
+mind however that the libudev-based device discovery may not be able
+to recognize such devices. If mouse events are sufficient, it may be
+better to use evdevmouse or tslib with such devices.
-To use this "driver", pass -plugin EvdevTouch on the command line.
+To use this plugin, pass -plugin EvdevTouch on the command line.
If automatic detection does not work, use -plugin
EvdevTouch:/dev/input/eventN to explicitly set the device file
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index 784cc2e38b..ff1a40bfc5 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -576,7 +576,8 @@ static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
}
QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
- QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
+ if (screen->rasterSurfaces())
+ QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
}
static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state)
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp
index bfb13811e3..3324d9ba49 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.cpp
+++ b/src/plugins/platforms/android/qandroidinputcontext.cpp
@@ -70,6 +70,35 @@ static jfieldID m_selectionStartFieldID = 0;
static jfieldID m_startOffsetFieldID = 0;
static jfieldID m_textFieldID = 0;
+static jboolean beginBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ BEGINBATCH";
+#endif
+
+ return m_androidInputContext->beginBatchEdit();
+
+ return JNI_TRUE;
+}
+
+static jboolean endBatchEdit(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ ENDBATCH";
+#endif
+
+ return m_androidInputContext->endBatchEdit();
+
+ return JNI_TRUE;
+}
+
+
static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
{
if (!m_androidInputContext)
@@ -121,12 +150,13 @@ static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars,
if (!m_androidInputContext)
return 0;
-#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
- qDebug() << "@@@ GETEX";
-#endif
const QAndroidInputContext::ExtractedText &extractedText =
m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
+#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL
+ qDebug() << "@@@ GETEX" << hintMaxChars << hintMaxLines << QString::fromLatin1("0x") + QString::number(flags,16) << extractedText.text << "partOff:" << extractedText.partialStartOffset << extractedText.partialEndOffset << "sel:" << extractedText.selectionStart << extractedText.selectionEnd << "offset:" << extractedText.startOffset;
+#endif
+
jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
env->SetIntField(object, m_partialEndOffsetFieldID, extractedText.partialEndOffset);
@@ -285,6 +315,8 @@ static jboolean updateCursorPosition(JNIEnv */*env*/, jobject /*thiz*/)
static JNINativeMethod methods[] = {
+ {"beginBatchEdit", "()Z", (void *)beginBatchEdit},
+ {"endBatchEdit", "()Z", (void *)endBatchEdit},
{"commitText", "(Ljava/lang/String;I)Z", (void *)commitText},
{"deleteSurroundingText", "(II)Z", (void *)deleteSurroundingText},
{"finishComposingText", "()Z", (void *)finishComposingText},
@@ -306,7 +338,7 @@ static JNINativeMethod methods[] = {
QAndroidInputContext::QAndroidInputContext()
- : QPlatformInputContext(), m_blockUpdateSelection(false)
+ : QPlatformInputContext(), m_blockUpdateSelection(false), m_batchEditNestingLevel(0)
{
QtAndroid::AttachedJNIEnv env;
if (!env.jniEnv)
@@ -416,11 +448,14 @@ void QAndroidInputContext::commit()
void QAndroidInputContext::updateCursorPosition()
{
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
- if (!query.isNull() && !m_blockUpdateSelection) {
+ if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
// make sure it also works with editors that have not been updated to the new API
QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
- QtAndroidInput::updateSelection(cursorPos, cursorPos, -1, -1); //selection empty and no pre-edit text
+ const int composeLength = m_composingText.length();
+ const int composeStart = composeLength ? cursorPos : -1;
+ QtAndroidInput::updateSelection(cursorPos + composeLength, cursorPos + composeLength, //empty selection
+ composeStart, composeStart + composeLength); // pre-edit text
}
}
@@ -507,6 +542,19 @@ void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodQueryEvent *
QCoreApplication::sendEvent(receiver, event);
}
+jboolean QAndroidInputContext::beginBatchEdit()
+{
+ ++m_batchEditNestingLevel;
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::endBatchEdit()
+{
+ if (--m_batchEditNestingLevel == 0 && !m_blockUpdateSelection) //ending batch edit mode
+ updateCursorPosition();
+ return JNI_TRUE;
+}
+
jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/)
{
m_composingText = text;
@@ -559,19 +607,39 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/)
{
+ // Note to self: "if the GET_EXTRACTED_TEXT_MONITOR flag is set, you should be calling
+ // updateExtractedText(View, int, ExtractedText) whenever you call
+ // updateSelection(View, int, int, int, int)." QTBUG-37980
+
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
if (query.isNull())
return m_extractedText;
- if (hintMaxChars)
- m_extractedText.text = query->value(Qt::ImSurroundingText).toString().right(hintMaxChars);
+ int localPos = query->value(Qt::ImCursorPosition).toInt(); //position before pre-edit text relative to the current block
+ QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
+ int blockPos = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; // position of the start of the current block
+ QString blockText = query->value(Qt::ImSurroundingText).toString() + m_composingText;
+ int composeLength = m_composingText.length();
+
+ int cpos = localPos + composeLength; //actual cursor pos relative to the current block
+
+ int localOffset = 0; // start of extracted text relative to the current block
+ if (hintMaxChars) {
+ if (cpos > hintMaxChars)
+ localOffset = cpos - hintMaxChars;
+ m_extractedText.text = blockText.mid(localOffset, hintMaxChars);
+ }
+
+ m_extractedText.startOffset = blockPos + localOffset; // "The offset in the overall text at which the extracted text starts."
- m_extractedText.startOffset = query->value(Qt::ImCursorPosition).toInt();
const QString &selection = query->value(Qt::ImCurrentSelection).toString();
const int selLen = selection.length();
if (selLen) {
- m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt();
- m_extractedText.selectionEnd = m_extractedText.startOffset;
+ m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt() - localOffset;
+ m_extractedText.selectionEnd = m_extractedText.selectionStart + selLen;
+ } else {
+ m_extractedText.selectionStart = cpos - localOffset;
+ m_extractedText.selectionEnd = cpos - localOffset;
}
return m_extractedText;
@@ -610,7 +678,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
{
QVariant textBefore = queryFocusObjectThreadSafe(Qt::ImTextBeforeCursor, QVariant(length));
if (textBefore.isValid()) {
- return textBefore.toString().left(length);
+ return textBefore.toString().left(length) + m_composingText;
}
//compatibility code for old controls that do not implement the new API
@@ -624,7 +692,7 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
return text;
const int wordLeftPos = cursorPos - length;
- return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos);
+ return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos) + m_composingText;
}
jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
@@ -647,11 +715,11 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur
sendInputMethodEvent(&event);
QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
- if (!query.isNull() && !m_blockUpdateSelection) {
+ if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) {
QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
const int cursorPos = absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt();
const int preeditLength = text.length();
- QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, cursorPos, cursorPos+preeditLength);
+ QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, -1, -1);
}
return JNI_TRUE;
@@ -713,9 +781,17 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end)
jboolean QAndroidInputContext::setSelection(jint start, jint end)
{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return JNI_FALSE;
+
+ int localPos = query->value(Qt::ImCursorPosition).toInt();
+ QVariant absolutePos = query->value(Qt::ImAbsolutePosition);
+ int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0;
+
QList<QInputMethodEvent::Attribute> attributes;
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
- start,
+ start - blockPosition,
end - start,
QVariant()));
diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h
index 2fb54a97c4..f7b29a855f 100644
--- a/src/plugins/platforms/android/qandroidinputcontext.h
+++ b/src/plugins/platforms/android/qandroidinputcontext.h
@@ -97,6 +97,8 @@ public:
void clear();
//---------------//
+ jboolean beginBatchEdit();
+ jboolean endBatchEdit();
jboolean commitText(const QString &text, jint newCursorPosition);
jboolean deleteSurroundingText(jint leftLength, jint rightLength);
jboolean finishComposingText();
@@ -133,6 +135,7 @@ private:
QString m_composingText;
QMetaObject::Connection m_updateCursorPosConnection;
bool m_blockUpdateSelection;
+ int m_batchEditNestingLevel;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
index e76eedbfd9..897feb5802 100644
--- a/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
+++ b/src/plugins/platforms/android/qandroidplatformdialoghelpers.cpp
@@ -41,6 +41,9 @@
#include "qandroidplatformdialoghelpers.h"
#include "androidjnimain.h"
+
+#include <QTextDocument>
+
#include <private/qguiapplication_p.h>
#include <qpa/qplatformtheme.h>
@@ -61,6 +64,14 @@ void QAndroidPlatformMessageDialogHelper::exec()
m_loop.exec();
}
+static QString htmlText(QString text)
+{
+ if (Qt::mightBeRichText(text))
+ return text;
+ text.remove(QLatin1Char('\r'));
+ return text.toHtmlEscaped().replace(QLatin1Char('\n'), QLatin1String("<br />"));
+}
+
bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
, Qt::WindowModality windowModality
, QWindow *parent)
@@ -74,19 +85,19 @@ bool QAndroidPlatformMessageDialogHelper::show(Qt::WindowFlags windowFlags
m_javaMessageDialog.callMethod<void>("setIcon", "(I)V", opt->icon());
- QString str = opt->windowTitle();
+ QString str = htmlText(opt->windowTitle());
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setTile", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
- str = opt->text();
+ str = htmlText(opt->text());
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
- str = opt->informativeText();
+ str = htmlText(opt->informativeText());
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setInformativeText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
- str = opt->detailedText();
+ str = htmlText(opt->detailedText());
if (!str.isEmpty())
m_javaMessageDialog.callMethod<void>("setDetailedText", "(Ljava/lang/String;)V", QJNIObjectPrivate::fromString(str).object());
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
index 7f68b44ed8..7423e6c55a 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.cpp
@@ -60,7 +60,17 @@ void QAndroidPlatformFontDatabase::populateFontDatabase()
QDir dir(fontpath, QLatin1String("*.ttf"));
for (int i = 0; i < int(dir.count()); ++i) {
const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
- addTTFile(QByteArray(), file);
+
+ QSupportedWritingSystems supportedWritingSystems;
+ QStringList families = addTTFile(QByteArray(), file, &supportedWritingSystems);
+
+ extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem);
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ if (i == QFontDatabase::Any || supportedWritingSystems.supported(QFontDatabase::WritingSystem(i))) {
+ QChar::Script script = QChar::Script(qt_script_for_writing_system(QFontDatabase::WritingSystem(i)));
+ m_fallbacks[script] += families;
+ }
+ }
}
}
@@ -71,9 +81,9 @@ QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &fami
{
Q_UNUSED(family);
Q_UNUSED(style);
- Q_UNUSED(script);
+
if (styleHint == QFont::Monospace)
- return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";");
+ return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";") + m_fallbacks[script];
- return QString(qgetenv("QT_ANDROID_FONTS")).split(";");
+ return QString(qgetenv("QT_ANDROID_FONTS")).split(";") + m_fallbacks[script];
}
diff --git a/src/plugins/platforms/android/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
index 3cbfe95d36..cdd3cf1674 100644
--- a/src/plugins/platforms/android/qandroidplatformfontdatabase.h
+++ b/src/plugins/platforms/android/qandroidplatformfontdatabase.h
@@ -53,6 +53,9 @@ public:
QFont::Style style,
QFont::StyleHint styleHint,
QChar::Script script) const;
+
+private:
+ QHash<QChar::Script, QStringList> m_fallbacks;
};
#endif // QANDROIDPLATFORMFONTDATABASE_H
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.cpp b/src/plugins/platforms/android/qandroidplatformintegration.cpp
index 9adefd5b2c..7f0f40be0f 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.cpp
+++ b/src/plugins/platforms/android/qandroidplatformintegration.cpp
@@ -41,6 +41,7 @@
#include "qandroidplatformintegration.h"
+#include <QtCore/private/qjni_p.h>
#include <QGuiApplication>
#include <QOpenGLContext>
#include <QThread>
@@ -103,9 +104,6 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
- if (!eglBindAPI(EGL_OPENGL_ES_API))
- qFatal("Could not bind GL_ES API");
-
m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (m_eglDisplay == EGL_NO_DISPLAY)
qFatal("Could not open egl display");
@@ -114,6 +112,9 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
if (!eglInitialize(m_eglDisplay, &major, &minor))
qFatal("Could not initialize egl display");
+ if (!eglBindAPI(EGL_OPENGL_ES_API))
+ qFatal("Could not bind GL_ES API");
+
m_primaryScreen = new QAndroidPlatformScreen();
screenAdded(m_primaryScreen);
m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth, m_defaultPhysicalSizeHeight));
@@ -130,9 +131,41 @@ QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &para
#endif
m_androidSystemLocale = new QAndroidSystemLocale;
+
+ QJNIObjectPrivate javaActivity(QtAndroid::activity());
+ if (javaActivity.isValid()) {
+ QJNIObjectPrivate resources = javaActivity.callObjectMethod("getResources", "()Landroid/content/res/Resources;");
+ QJNIObjectPrivate configuration = resources.callObjectMethod("getConfiguration", "()Landroid/content/res/Configuration;");
+
+ int touchScreen = configuration.getField<jint>("touchscreen");
+ if (touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_FINGER")
+ || touchScreen == QJNIObjectPrivate::getStaticField<jint>("android/content/res/Configuration", "TOUCHSCREEN_STYLUS"))
+ {
+ m_touchDevice = new QTouchDevice;
+ m_touchDevice->setType(QTouchDevice::TouchScreen);
+ m_touchDevice->setCapabilities(QTouchDevice::Position
+ | QTouchDevice::Area
+ | QTouchDevice::Pressure
+ | QTouchDevice::NormalizedPosition);
+
+ QJNIObjectPrivate pm = javaActivity.callObjectMethod("getPackageManager", "()Landroid/content/pm/PackageManager;");
+ Q_ASSERT(pm.isValid());
+ if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
+ QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND", "Ljava/lang/String;").object())) {
+ m_touchDevice->setMaximumTouchPoints(10);
+ } else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
+ QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT", "Ljava/lang/String;").object())) {
+ m_touchDevice->setMaximumTouchPoints(4);
+ } else if (pm.callMethod<jboolean>("hasSystemFeature","(Ljava/lang/String;)Z",
+ QJNIObjectPrivate::getStaticObjectField("android/content/pm/PackageManager", "FEATURE_TOUCHSCREEN_MULTITOUCH", "Ljava/lang/String;").object())) {
+ m_touchDevice->setMaximumTouchPoints(2);
+ }
+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+ }
+ }
}
-bool QAndroidPlatformIntegration::needsWorkaround()
+bool QAndroidPlatformIntegration::needsBasicRenderloopWorkaround()
{
static bool needsWorkaround =
QtAndroid::deviceName().compare(QStringLiteral("samsung SM-T211"), Qt::CaseInsensitive) == 0
@@ -150,7 +183,7 @@ bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
case OpenGL: return true;
case ForeignWindows: return true;
case ThreadedOpenGL:
- if (needsWorkaround())
+ if (needsBasicRenderloopWorkaround())
return false;
else
return true;
diff --git a/src/plugins/platforms/android/qandroidplatformintegration.h b/src/plugins/platforms/android/qandroidplatformintegration.h
index 2d685bc567..4a3fe6c766 100644
--- a/src/plugins/platforms/android/qandroidplatformintegration.h
+++ b/src/plugins/platforms/android/qandroidplatformintegration.h
@@ -120,9 +120,9 @@ public:
QTouchDevice *touchDevice() const { return m_touchDevice; }
void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
- static bool needsWorkaround();
EGLDisplay m_eglDisplay;
private:
+ static bool needsBasicRenderloopWorkaround();
QTouchDevice *m_touchDevice;
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
index a0b3ae066c..289480c625 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.cpp
@@ -62,6 +62,22 @@ void QAndroidPlatformOpenGLContext::swapBuffers(QPlatformSurface *surface)
static_cast<QAndroidPlatformOpenGLWindow *>(surface)->checkNativeSurface(eglConfig());
}
+bool QAndroidPlatformOpenGLContext::needsFBOReadBackWorkaroud()
+{
+ static bool set = false;
+ static bool needsWorkaround = false;
+
+ if (!set) {
+ const char *rendererString = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
+ needsWorkaround =
+ qstrcmp(rendererString, "Mali-400 MP") == 0
+ || qstrcmp(rendererString, "Adreno (TM) 200") == 0;
+ set = true;
+ }
+
+ return needsWorkaround;
+}
+
bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface)
{
bool ret = QEGLPlatformContext::makeCurrent(surface);
@@ -71,7 +87,7 @@ bool QAndroidPlatformOpenGLContext::makeCurrent(QPlatformSurface *surface)
if (rendererString != 0 && qstrncmp(rendererString, "Android Emulator", 16) == 0)
ctx_d->workaround_missingPrecisionQualifiers = true;
- if (!ctx_d->workaround_brokenFBOReadBack && QAndroidPlatformIntegration::needsWorkaround())
+ if (!ctx_d->workaround_brokenFBOReadBack && needsFBOReadBackWorkaroud())
ctx_d->workaround_brokenFBOReadBack = true;
return ret;
diff --git a/src/plugins/platforms/android/qandroidplatformopenglcontext.h b/src/plugins/platforms/android/qandroidplatformopenglcontext.h
index 29e5f596d5..10a89d541b 100644
--- a/src/plugins/platforms/android/qandroidplatformopenglcontext.h
+++ b/src/plugins/platforms/android/qandroidplatformopenglcontext.h
@@ -56,6 +56,8 @@ public:
private:
virtual EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface);
+
+ static bool needsFBOReadBackWorkaroud();
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp
index 334b9cdd23..eb5a73c4a3 100644
--- a/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp
+++ b/src/plugins/platforms/android/qandroidplatformrasterwindow.cpp
@@ -57,7 +57,7 @@ void QAndroidPlatformRasterWindow::repaint(const QRegion &region)
if (QAndroidPlatformWindow::parent())
return;
- QRect currentGeometry = geometry().translated(mapToGlobal(QPoint(0,0)));
+ QRect currentGeometry = geometry();
QRect dirtyClient = region.boundingRect();
QRect dirtyRegion(currentGeometry.left() + dirtyClient.left(),
@@ -74,7 +74,7 @@ void QAndroidPlatformRasterWindow::repaint(const QRegion &region)
void QAndroidPlatformRasterWindow::setGeometry(const QRect &rect)
{
- m_oldGeometry = geometry().translated(mapToGlobal(QPoint(0,0)));;
+ m_oldGeometry = geometry();
QAndroidPlatformWindow::setGeometry(rect);
}
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.cpp b/src/plugins/platforms/android/qandroidplatformscreen.cpp
index dbf317696f..678f4e6b5a 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.cpp
+++ b/src/plugins/platforms/android/qandroidplatformscreen.cpp
@@ -133,8 +133,10 @@ void QAndroidPlatformScreen::addWindow(QAndroidPlatformWindow *window)
return;
m_windowStack.prepend(window);
- if (window->isRaster())
+ if (window->isRaster()) {
+ m_rasterSurfaces.ref();
setDirty(window->geometry());
+ }
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
@@ -148,8 +150,10 @@ void QAndroidPlatformScreen::removeWindow(QAndroidPlatformWindow *window)
m_windowStack.removeOne(window);
if (window->isRaster()) {
+ m_rasterSurfaces.deref();
setDirty(window->geometry());
}
+
QWindow *w = topWindow();
QWindowSystemInterface::handleWindowActivated(w);
topWindowChanged(w);
@@ -238,6 +242,11 @@ void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
}
}
+int QAndroidPlatformScreen::rasterSurfaces()
+{
+ return m_rasterSurfaces;
+}
+
void QAndroidPlatformScreen::doRedraw()
{
PROFILE_SCOPE;
@@ -246,7 +255,7 @@ void QAndroidPlatformScreen::doRedraw()
return;
QMutexLocker lock(&m_surfaceMutex);
- if (m_id == -1) {
+ if (m_id == -1 && m_rasterSurfaces) {
m_id = QtAndroid::createSurface(this, m_geometry, true, m_depth);
m_surfaceWaitCondition.wait(&m_surfaceMutex);
}
diff --git a/src/plugins/platforms/android/qandroidplatformscreen.h b/src/plugins/platforms/android/qandroidplatformscreen.h
index 625e77840e..96a91fbf06 100644
--- a/src/plugins/platforms/android/qandroidplatformscreen.h
+++ b/src/plugins/platforms/android/qandroidplatformscreen.h
@@ -82,6 +82,7 @@ public:
void scheduleUpdate();
void topWindowChanged(QWindow *w);
+ int rasterSurfaces();
public slots:
void setDirty(const QRect &rect);
@@ -110,6 +111,7 @@ private slots:
private:
int m_id = -1;
+ QAtomicInt m_rasterSurfaces = 0;
ANativeWindow* m_nativeSurface = nullptr;
QWaitCondition m_surfaceWaitCondition;
};
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 0f99a414a0..990acd5301 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -298,7 +298,8 @@ bool hasValueAttribute(QAccessibleInterface *interface)
Q_ASSERT(interface);
const QAccessible::Role qtrole = interface->role();
if (qtrole == QAccessible::EditableText
- || interface->valueInterface()) {
+ || interface->valueInterface()
+ || interface->state().checkable) {
return true;
}
@@ -330,6 +331,10 @@ id getValueAttribute(QAccessibleInterface *interface)
return QCFString::toNSString(QString::number(valueInterface->currentValue().toDouble()));
}
+ if (interface->state().checkable) {
+ return [NSNumber numberWithInt: (interface->state().checked ? 1 : 0)];
+ }
+
return nil;
}
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index bc98d002f0..0b674b8d2f 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -417,7 +417,23 @@
}
- (id)accessibilityFocusedUIElement {
- return NSAccessibilityUnignoredAncestor(self);
+ QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
+
+ if (!iface || !iface->isValid()) {
+ qWarning() << "FocusedUIElement for INVALID";
+ return nil;
+ }
+ QAccessibleInterface *childInterface = iface->focusChild();
+ if (childInterface) {
+ QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
+ // FIXME: parent could be wrong
+ QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self];
+ [accessibleElement autorelease];
+ return accessibleElement;
+ }
+
+ // no focus found
+ return nil;
}
@end
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index 33d7dcbcf4..0274ed8201 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -163,6 +163,7 @@ public:
// The following variables help organizing modal sessions:
QStack<QCocoaModalSessionInfo> cocoaModalSessionStack;
bool currentExecIsNSAppRun;
+ bool modalSessionOnNSAppRun;
bool nsAppRunCalledByQt;
bool cleanupModalSessionsNeeded;
uint processEventsCalled;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index 91b631bff9..495a54cac4 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -721,7 +721,6 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
// setting currentModalSessionCached to zero, so that interrupt() calls
// [NSApp abortModal] if another modal session is currently running
Q_Q(QCocoaEventDispatcher);
- q->interrupt();
// Add a new, empty (null), NSModalSession to the stack.
// It will become active the next time QEventDispatcher::processEvents is called.
@@ -734,6 +733,12 @@ void QCocoaEventDispatcherPrivate::beginModalSession(QWindow *window)
cocoaModalSessionStack.push(info);
updateChildrenWorksWhenModal();
currentModalSessionCached = 0;
+ if (currentExecIsNSAppRun) {
+ modalSessionOnNSAppRun = true;
+ q->wakeUp();
+ } else {
+ q->interrupt();
+ }
}
void QCocoaEventDispatcherPrivate::endModalSession(QWindow *window)
@@ -772,6 +777,7 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
runLoopTimerRef(0),
blockSendPostedEvents(false),
currentExecIsNSAppRun(false),
+ modalSessionOnNSAppRun(false),
nsAppRunCalledByQt(false),
cleanupModalSessionsNeeded(false),
processEventsCalled(0),
@@ -902,6 +908,14 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info)
// processEvents() was called "manually," ignore this source for now
d->maybeCancelWaitForMoreEvents();
return;
+ } else if (d->modalSessionOnNSAppRun) {
+ // We're about to spawn the 1st modal session on top of the main runloop.
+ // Instead of calling processPostedEvents(), which would need us stop
+ // NSApp, we just re-enter processEvents(). This is equivalent to calling
+ // QDialog::exec() except that it's done in a non-blocking way.
+ d->modalSessionOnNSAppRun = false;
+ d->q_func()->processEvents(QEventLoop::DialogExec | QEventLoop::EventLoopExec | QEventLoop::WaitForMoreEvents);
+ return;
}
d->processPostedEvents();
d->maybeCancelWaitForMoreEvents();
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 65a9f87e2d..412818ae47 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -316,11 +316,17 @@ QCocoaIntegration *QCocoaIntegration::instance()
*/
void QCocoaIntegration::updateScreens()
{
- NSArray *screens = [NSScreen screens];
+ NSArray *scrs = [NSScreen screens];
+ NSMutableArray *screens = [NSMutableArray arrayWithArray:scrs];
+ if ([screens count] == 0)
+ if ([NSScreen mainScreen])
+ [screens addObject:[NSScreen mainScreen]];
+ if ([screens count] == 0)
+ return;
QSet<QCocoaScreen*> remainingScreens = QSet<QCocoaScreen*>::fromList(mScreens);
QList<QPlatformScreen *> siblings;
for (uint i = 0; i < [screens count]; i++) {
- NSScreen* scr = [[NSScreen screens] objectAtIndex:i];
+ NSScreen* scr = [screens objectAtIndex:i];
CGDirectDisplayID dpy = [[[scr deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue];
// If this screen is a mirror and is not the primary one of the mirror set, ignore it.
if (CGDisplayIsInMirrorSet(dpy)) {
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 6e1f00eebe..b7a6a14d4a 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -183,6 +183,7 @@ public:
void windowWillMove();
void windowDidMove();
void windowDidResize();
+ void windowDidEndLiveResize();
bool windowShouldClose();
bool windowIsPopupType(Qt::WindowType type = Qt::Widget) const;
@@ -252,6 +253,7 @@ public: // for QNSView
QList<QCocoaWindow *> m_childWindows;
Qt::WindowFlags m_windowFlags;
+ bool m_effectivelyMaximized;
Qt::WindowState m_synchedWindowState;
Qt::WindowModality m_windowModality;
QPointer<QWindow> m_activePopupWindow;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index c7fba4eef0..b27e1b03db 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -352,6 +352,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_contentViewIsToBeEmbedded(false)
, m_parentCocoaWindow(0)
, m_isNSWindowChild(false)
+ , m_effectivelyMaximized(false)
, m_synchedWindowState(Qt::WindowActive)
, m_windowModality(Qt::NonModal)
, m_windowUnderMouse(false)
@@ -1164,6 +1165,14 @@ void QCocoaWindow::windowDidResize()
[m_qtView updateGeometry];
}
+void QCocoaWindow::windowDidEndLiveResize()
+{
+ if (m_synchedWindowState == Qt::WindowMaximized && ![m_nsWindow isZoomed]) {
+ m_effectivelyMaximized = false;
+ [m_qtView notifyWindowStateChanged:Qt::WindowNoState];
+ }
+}
+
bool QCocoaWindow::windowShouldClose()
{
bool accepted = false;
@@ -1436,7 +1445,6 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
{
if (!m_nsWindow)
return;
-
// if content view width or height is 0 then the window animations will crash so
// do nothing except set the new state
NSRect contentRect = [contentView() frame];
@@ -1446,9 +1454,7 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
return;
}
- if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized)) {
- [m_nsWindow performZoom : m_nsWindow]; // toggles
- }
+ Qt::WindowState predictedState = newState;
if ((m_synchedWindowState & Qt::WindowMinimized) != (newState & Qt::WindowMinimized)) {
if (newState & Qt::WindowMinimized) {
@@ -1458,12 +1464,26 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
}
}
+ if ((m_synchedWindowState & Qt::WindowMaximized) != (newState & Qt::WindowMaximized) || (m_effectivelyMaximized && newState == Qt::WindowNoState)) {
+ if ((m_synchedWindowState & Qt::WindowFullScreen) == (newState & Qt::WindowFullScreen)) {
+ [m_nsWindow performZoom : m_nsWindow]; // toggles
+ m_effectivelyMaximized = !m_effectivelyMaximized;
+ } else if (!(newState & Qt::WindowMaximized)) {
+ // it would be nice to change the target geometry that toggleFullScreen will animate toward
+ // but there is no known way, so the maximized state is not possible at this time
+ predictedState = static_cast<Qt::WindowState>(static_cast<int>(newState) | Qt::WindowMaximized);
+ m_effectivelyMaximized = true;
+ }
+ }
+
if ((m_synchedWindowState & Qt::WindowFullScreen) != (newState & Qt::WindowFullScreen)) {
bool fakeFullScreen = true;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) {
if (window()->flags() & Qt::WindowFullscreenButtonHint) {
fakeFullScreen = false;
+ if (m_effectivelyMaximized && m_synchedWindowState == Qt::WindowFullScreen)
+ predictedState = Qt::WindowMaximized;
[m_nsWindow toggleFullScreen : m_nsWindow];
}
}
@@ -1490,8 +1510,12 @@ void QCocoaWindow::syncWindowState(Qt::WindowState newState)
}
}
+#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
+ qDebug() << "QCocoaWindow::syncWindowState" << newState << "actual" << predictedState << "was" << m_synchedWindowState << "effectively maximized" << m_effectivelyMaximized;
+#endif
+
// New state is now the current synched state
- m_synchedWindowState = newState;
+ m_synchedWindowState = predictedState;
}
bool QCocoaWindow::setWindowModified(bool modified)
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 47081ab890..1197aa9148 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -281,6 +281,12 @@ static QTouchDevice *touchDevice = 0;
- (void)notifyWindowStateChanged:(Qt::WindowState)newState
{
+ // If the window was maximized, then fullscreen, then tried to go directly to "normal" state,
+ // this notification will say that it is "normal", but it will still look maximized, and
+ // if you called performZoom it would actually take it back to "normal".
+ // So we should say that it is maximized because it actually is.
+ if (newState == Qt::WindowNoState && m_platformWindow->m_effectivelyMaximized)
+ newState = Qt::WindowMaximized;
QWindowSystemInterface::handleWindowStateChanged(m_window, newState);
// We want to read the window state back from the window,
// but the event we just sent may be asynchronous.
@@ -346,6 +352,8 @@ static QTouchDevice *touchDevice = 0;
- (void)notifyWindowWillZoom:(BOOL)willZoom
{
Qt::WindowState newState = willZoom ? Qt::WindowMaximized : Qt::WindowNoState;
+ if (!willZoom)
+ m_platformWindow->m_effectivelyMaximized = false;
[self notifyWindowStateChanged:newState];
}
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index a438950a55..31e3e343b9 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -54,6 +54,15 @@
@implementation QNSView (QNSViewAccessibility)
+- (id)childAccessibleElement {
+ if (!m_window->accessibleRoot())
+ return nil;
+
+ QAccessible::Id childId = QAccessible::uniqueId(m_window->accessibleRoot());
+ QCocoaAccessibleElement *child = [QCocoaAccessibleElement createElementWithId: childId parent: self];
+ return [child autorelease];
+}
+
// The QNSView is a container that the user does not interact directly with:
// Remove it from the user-visible accessibility tree.
- (BOOL)accessibilityIsIgnored {
@@ -61,58 +70,22 @@
}
- (id)accessibilityAttributeValue:(NSString *)attribute {
-
// activate accessibility updates
QCocoaIntegration::instance()->accessibility()->setActive(true);
- if ([attribute isEqualToString:NSAccessibilityRoleAttribute]) {
- if (m_window->accessibleRoot())
- return QCocoaAccessible::macRole(m_window->accessibleRoot());
- return NSAccessibilityUnknownRole;
- } else if ([attribute isEqualToString:NSAccessibilityRoleDescriptionAttribute]) {
- return NSAccessibilityRoleDescriptionForUIElement(self);
- } else if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
- if (!m_window->accessibleRoot())
- return [super accessibilityAttributeValue:attribute];
- return QCocoaAccessible::unignoredChildren(self, m_window->accessibleRoot());
+ if ([attribute isEqualToString:NSAccessibilityChildrenAttribute]) {
+ return NSAccessibilityUnignoredChildrenForOnlyChild([self childAccessibleElement]);
} else {
return [super accessibilityAttributeValue:attribute];
}
}
- (id)accessibilityHitTest:(NSPoint)point {
- if (!m_window->accessibleRoot())
- return [super accessibilityHitTest:point];
-
- QAccessibleInterface *childInterface = m_window->accessibleRoot()->childAt(point.x, qt_mac_flipYCoordinate(point.y));
- // No child found, meaning we hit the NSView
- if (!childInterface) {
- return [super accessibilityHitTest:point];
- }
-
- // Hit a child, forward to child accessible interface.
- QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
- // FIXME: parent could be wrong
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self ];
- [accessibleElement autorelease];
- return [accessibleElement accessibilityHitTest:point];
+ return [[self childAccessibleElement] accessibilityHitTest: point];
}
- (id)accessibilityFocusedUIElement {
- if (!m_window->accessibleRoot())
- return [super accessibilityFocusedUIElement];
-
- QAccessibleInterface *childInterface = m_window->accessibleRoot()->focusChild();
- if (childInterface) {
- QAccessible::Id childAxid = QAccessible::uniqueId(childInterface);
- // FIXME: parent could be wrong
- QCocoaAccessibleElement *accessibleElement = [QCocoaAccessibleElement createElementWithId:childAxid parent:self];
- [accessibleElement autorelease];
- return accessibleElement;
- }
-
- // should not happen
- return nil;
+ return [[self childAccessibleElement] accessibilityFocusedUIElement];
}
@end
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.mm b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
index c9b3d69381..d9509098c6 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.mm
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.mm
@@ -75,6 +75,14 @@
}
}
+- (void)windowDidEndLiveResize:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ if (m_cocoaWindow) {
+ m_cocoaWindow->windowDidEndLiveResize();
+ }
+}
+
- (void)windowWillMove:(NSNotification *)notification
{
Q_UNUSED(notification);
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index 9083abc562..4d443b91e3 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -53,8 +53,8 @@
QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share, EGLDisplay display)
- : QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display,
- QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)))
+ : QEGLPlatformContext(format, share, display,
+ QEglFSIntegration::chooseConfig(display, format))
{
}
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
index dfb766db32..4aa3f29260 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
@@ -141,7 +141,16 @@ QImage::Format QEglFSHooks::screenFormat() const
QSurfaceFormat QEglFSHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
{
- return inputFormat;
+ QSurfaceFormat format = inputFormat;
+
+ static const bool force888 = qgetenv("QT_QPA_EGLFS_FORCE888").toInt();
+ if (force888) {
+ format.setRedBufferSize(8);
+ format.setGreenBufferSize(8);
+ format.setBlueBufferSize(8);
+ }
+
+ return format;
}
bool QEglFSHooks::filterConfig(EGLDisplay, EGLConfig) const
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
index c48a0251a9..52357a5d58 100644
--- a/src/plugins/platforms/ios/qioscontext.h
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -85,10 +85,12 @@ private:
GLuint depthRenderbuffer;
GLint renderbufferWidth;
GLint renderbufferHeight;
+ bool isComplete;
};
static void deleteBuffers(const FramebufferObject &framebufferObject);
+ FramebufferObject &backingFramebufferObjectFor(QPlatformSurface *) const;
mutable QHash<QIOSWindow *, FramebufferObject> m_framebufferObjects;
};
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
index 7310d2904f..ddee52196a 100644
--- a/src/plugins/platforms/ios/qioscontext.mm
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -94,14 +94,38 @@ QSurfaceFormat QIOSContext::format() const
return m_format;
}
+#define QT_IOS_GL_STATUS_CASE(val) case val: return QLatin1Literal(#val)
+
+static QString fboStatusString(GLenum status)
+{
+ switch (status) {
+ QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT);
+ QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS);
+ QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT);
+ QT_IOS_GL_STATUS_CASE(GL_FRAMEBUFFER_UNSUPPORTED);
+ default:
+ return QString(QStringLiteral("unknown status: %x")).arg(status);
+ }
+}
+
bool QIOSContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
[EAGLContext setCurrentContext:m_eaglContext];
- glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject(surface));
- return true;
+ // For offscreen surfaces we don't prepare a default FBO
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return true;
+
+ FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
+
+ // We bind the default FBO even if it's incomplete, so that clients who
+ // call glCheckFramebufferStatus as a result of this function returning
+ // false will get a matching error code.
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
+
+ return framebufferObject.isComplete;
}
void QIOSContext::doneCurrent()
@@ -112,17 +136,26 @@ void QIOSContext::doneCurrent()
void QIOSContext::swapBuffers(QPlatformSurface *surface)
{
Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
- Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
- QIOSWindow *window = static_cast<QIOSWindow *>(surface);
- Q_ASSERT(m_framebufferObjects.contains(window));
+
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ return; // Nothing to do
+
+ FramebufferObject &framebufferObject = backingFramebufferObjectFor(surface);
[EAGLContext setCurrentContext:m_eaglContext];
- glBindRenderbuffer(GL_RENDERBUFFER, m_framebufferObjects[window].colorRenderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
[m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
}
-GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
+QIOSContext::FramebufferObject &QIOSContext::backingFramebufferObjectFor(QPlatformSurface *surface) const
{
+ // We keep track of default-FBOs in the root context of a share-group. This assumes
+ // that the contexts form a tree, where leaf nodes are always destroyed before their
+ // parents. If that assumption (based on the current implementation) doesn't hold we
+ // should probably use QOpenGLMultiGroupSharedResource to track the shared default-FBOs.
+ if (m_sharedContext)
+ return m_sharedContext->backingFramebufferObjectFor(surface);
+
Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
QIOSWindow *window = static_cast<QIOSWindow *>(surface);
@@ -181,11 +214,27 @@ GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
}
- if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
- NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ framebufferObject.isComplete = glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
+
+ if (!framebufferObject.isComplete) {
+ qWarning("QIOSContext failed to make complete framebuffer object (%s)",
+ qPrintable(fboStatusString(glCheckFramebufferStatus(GL_FRAMEBUFFER))));
+ }
+ }
+
+ return framebufferObject;
+}
+
+GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
+{
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen) {
+ // Binding and rendering to the zero-FBO on iOS seems to be
+ // no-ops, so we can safely return 0 here, even if it's not
+ // really a valid FBO on iOS.
+ return 0;
}
- return framebufferObject.handle;
+ return backingFramebufferObjectFor(surface).handle;
}
void QIOSContext::windowDestroyed(QObject *object)
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
index 13a0b46745..9a2c55f7f2 100644
--- a/src/plugins/platforms/ios/qiosinputcontext.mm
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -47,6 +47,7 @@
#include "qioswindow.h"
#include "quiview.h"
#include <QGuiApplication>
+#include <QtGui/private/qwindow_p.h>
@interface QIOSKeyboardListener : UIGestureRecognizer {
@public
@@ -54,6 +55,8 @@
BOOL m_keyboardVisible;
BOOL m_keyboardVisibleAndDocked;
BOOL m_ignoreKeyboardChanges;
+ BOOL m_touchPressWhileKeyboardVisible;
+ BOOL m_keyboardHiddenByGesture;
QRectF m_keyboardRect;
QRectF m_keyboardEndRect;
NSTimeInterval m_duration;
@@ -72,6 +75,8 @@
m_keyboardVisible = NO;
m_keyboardVisibleAndDocked = NO;
m_ignoreKeyboardChanges = NO;
+ m_touchPressWhileKeyboardVisible = NO;
+ m_keyboardHiddenByGesture = NO;
m_duration = 0;
m_curve = UIViewAnimationCurveEaseOut;
m_viewController = 0;
@@ -145,9 +150,6 @@
- (void) keyboardDidChangeFrame:(NSNotification *)notification
{
Q_UNUSED(notification);
- if (m_ignoreKeyboardChanges)
- return;
-
[self handleKeyboardRectChanged];
// If the keyboard was visible and docked from before, this is just a geometry
@@ -178,7 +180,11 @@
// Note that UIKeyboardWillHideNotification is also sendt when the keyboard is undocked.
m_keyboardVisibleAndDocked = NO;
m_keyboardEndRect = [self getKeyboardRect:notification];
- self.enabled = NO;
+ if (!m_keyboardHiddenByGesture) {
+ // Only disable the gesture if the hiding of the keyboard was not caused by it.
+ // Otherwise we need to await the final touchEnd callback for doing some clean-up.
+ self.enabled = NO;
+ }
m_context->scroll(0);
}
@@ -201,12 +207,45 @@
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
QPointF p = fromCGPoint([[touches anyObject] locationInView:m_viewController.view]);
- if (m_keyboardRect.contains(p))
+ if (m_keyboardRect.contains(p)) {
+ m_keyboardHiddenByGesture = YES;
m_context->hideInputPanel();
+ }
[super touchesMoved:touches withEvent:event];
}
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ Q_ASSERT(m_keyboardVisibleAndDocked);
+ m_touchPressWhileKeyboardVisible = YES;
+ [super touchesBegan:touches withEvent:event];
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ m_touchPressWhileKeyboardVisible = NO;
+ [self performSelectorOnMainThread:@selector(touchesEndedPostDelivery) withObject:nil waitUntilDone:NO];
+ [super touchesEnded:touches withEvent:event];
+}
+
+- (void)touchesEndedPostDelivery
+{
+ // Do some clean-up _after_ touchEnd has been delivered to QUIView
+ m_keyboardHiddenByGesture = NO;
+ if (!m_keyboardVisibleAndDocked) {
+ self.enabled = NO;
+ if (qApp->focusObject()) {
+ // UI Controls are told to gain focus on touch release. So when the 'hide keyboard' gesture
+ // finishes, the final touch end can trigger a control to gain focus. This is in conflict with
+ // the gesture, so we clear focus once more as a work-around.
+ static_cast<QWindowPrivate *>(QObjectPrivate::get(qApp->focusWindow()))->clearFocusObject();
+ }
+ } else {
+ m_context->scrollToCursor();
+ }
+}
+
@end
QIOSInputContext::QIOSInputContext()
@@ -233,6 +272,12 @@ QRectF QIOSInputContext::keyboardRect() const
void QIOSInputContext::showInputPanel()
{
+ if (m_keyboardListener->m_keyboardHiddenByGesture) {
+ // We refuse to re-show the keyboard until the touch
+ // sequence that triggered the gesture has ended.
+ return;
+ }
+
// Documentation tells that one should call (and recall, if necessary) becomeFirstResponder/resignFirstResponder
// to show/hide the keyboard. This is slightly inconvenient, since there exist no API to get the current first
// responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use.
@@ -306,6 +351,13 @@ void QIOSInputContext::scrollToCursor()
if (!isQtApplication() || !m_focusView)
return;
+ if (m_keyboardListener->m_touchPressWhileKeyboardVisible) {
+ // Don't scroll to the cursor if the user is touching the screen. This
+ // interferes with selection and the 'hide keyboard' gesture. Instead
+ // we update scrolling upon touchEnd.
+ return;
+ }
+
UIView *view = m_keyboardListener->m_viewController.view;
if (view.window != m_focusView.window)
return;
@@ -332,7 +384,7 @@ void QIOSInputContext::scroll(int y)
newBounds.origin.y = y;
QPointer<QIOSInputContext> self = this;
[UIView animateWithDuration:m_keyboardListener->m_duration delay:0
- options:m_keyboardListener->m_curve
+ options:m_keyboardListener->m_curve | UIViewAnimationOptionBeginFromCurrentState
animations:^{ view.bounds = newBounds; }
completion:^(BOOL){
if (self)
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
index a28926ff99..956c112399 100644
--- a/src/plugins/platforms/ios/qiosintegration.h
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -64,6 +64,7 @@ public:
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const Q_DECL_OVERRIDE;
QPlatformFontDatabase *fontDatabase() const;
QPlatformClipboard *clipboard() const;
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
index 7a40e349c9..0fe7adff9f 100644
--- a/src/plugins/platforms/ios/qiosintegration.mm
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -51,6 +51,8 @@
#include "qiostheme.h"
#include "qiosservices.h"
+#include <qpa/qplatformoffscreensurface.h>
+
#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
#include <QtPlatformSupport/private/qmacmime_p.h>
#include <QDir>
@@ -144,6 +146,11 @@ QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLCont
return new QIOSContext(context);
}
+QPlatformOffscreenSurface *QIOSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+ return new QPlatformOffscreenSurface(surface);
+}
+
QAbstractEventDispatcher *QIOSIntegration::createEventDispatcher() const
{
if (isQtApplication())
diff --git a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
index aca8d76041..72d5833e73 100644
--- a/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
+++ b/src/plugins/platforms/linuxfb/qlinuxfbscreen.cpp
@@ -360,7 +360,7 @@ bool QLinuxFbScreen::initialize()
// Open the device
mFbFd = openFramebufferDevice(fbDevice);
if (mFbFd == -1) {
- qWarning("Failed to open framebuffer %s : %s", qPrintable(fbDevice), strerror(errno));
+ qErrnoWarning(errno, "Failed to open framebuffer %s", qPrintable(fbDevice));
return false;
}
@@ -371,12 +371,12 @@ bool QLinuxFbScreen::initialize()
memset(&finfo, 0, sizeof(finfo));
if (ioctl(mFbFd, FBIOGET_FSCREENINFO, &finfo) != 0) {
- qWarning("Error reading fixed information: %s", strerror(errno));
+ qErrnoWarning(errno, "Error reading fixed information");
return false;
}
if (ioctl(mFbFd, FBIOGET_VSCREENINFO, &vinfo)) {
- qWarning("Error reading variable information: %s", strerror(errno));
+ qErrnoWarning(errno, "Error reading variable information");
return false;
}
@@ -391,7 +391,7 @@ bool QLinuxFbScreen::initialize()
mMmap.size = finfo.smem_len;
uchar *data = (unsigned char *)mmap(0, mMmap.size, PROT_READ | PROT_WRITE, MAP_SHARED, mFbFd, 0);
if ((long)data == -1) {
- qWarning("Failed to mmap framebuffer: %s", strerror(errno));
+ qErrnoWarning(errno, "Failed to mmap framebuffer");
return false;
}
@@ -420,10 +420,12 @@ bool QLinuxFbScreen::initialize()
mTtyFd = openTtyDevice(ttyDevice);
if (mTtyFd == -1)
- qWarning() << "Failed to open tty" << strerror(errno);
+ qErrnoWarning(errno, "Failed to open tty");
- if (doSwitchToGraphicsMode && !switchToGraphicsMode(mTtyFd, &mOldTtyMode))
- qWarning() << "Failed to set graphics mode" << strerror(errno);
+ if (doSwitchToGraphicsMode)
+ switchToGraphicsMode(mTtyFd, &mOldTtyMode);
+ // Do not warn if the switch fails: the ioctl fails when launching from
+ // a remote console and there is nothing we can do about it.
blankScreen(mFbFd, false);
diff --git a/src/plugins/platforms/qnx/qqnxfilepicker.cpp b/src/plugins/platforms/qnx/qqnxfilepicker.cpp
index 830b110f2a..08119ce0ae 100644
--- a/src/plugins/platforms/qnx/qqnxfilepicker.cpp
+++ b/src/plugins/platforms/qnx/qqnxfilepicker.cpp
@@ -130,9 +130,9 @@ void QQnxFilePicker::open()
map[QStringLiteral("AllowOverwrite")] = false;
if (!m_defaultSaveFileNames.isEmpty())
- map[QStringLiteral("DefaultFileNames")] = m_defaultSaveFileNames.join(",");
+ map[QStringLiteral("DefaultFileNames")] = m_defaultSaveFileNames.join(QLatin1Char(','));
if (!m_filters.isEmpty())
- map[QStringLiteral("Filter")] = m_filters.join(";");
+ map[QStringLiteral("Filter")] = m_filters.join(QLatin1Char(';'));
QByteArray ppsData;
#if defined(Q_OS_BLACKBERRY_TABLET)
@@ -288,8 +288,8 @@ QString QQnxFilePicker::filePickerType() const
bool video = false;
bool music = false;
QMimeDatabase mimeDb;
- for (int i = 0; i < filters().count(); i++) {
- QList<QMimeType> mimeTypes = mimeDb.mimeTypesForFileName(filters().at(i));
+ for (int i = 0; i < m_filters.count(); i++) {
+ QList<QMimeType> mimeTypes = mimeDb.mimeTypesForFileName(m_filters.at(i));
if (mimeTypes.isEmpty())
return QStringLiteral("Other");
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index a6c69164c7..2707f14db2 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -177,6 +177,11 @@ QQnxScreen::QQnxScreen(screen_context_t screenContext, screen_display_t display,
m_currentGeometry = m_initialGeometry = QRect(0, 0, val[0], val[1]);
+ char name[100];
+ Q_SCREEN_CHECKERROR(screen_get_display_property_cv(m_display, SCREEN_PROPERTY_ID_STRING, 100,
+ name), "Failed to query display name");
+ m_name = QString::fromUtf8(name);
+
// Cache size of this display in millimeters. We have to take care of the orientation.
// libscreen always reports the physical size dimensions as width and height in the
// native orientation. Contrary to this, QPlatformScreen::physicalSize() expects the
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index d39a210d4b..a0b760135f 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -77,6 +77,8 @@ public:
int rotation() const { return m_currentRotation; }
+ QString name() const { return m_name; }
+
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; }
@@ -132,6 +134,7 @@ private:
int m_initialRotation;
int m_currentRotation;
int m_keyboardHeight;
+ QString m_name;
QSize m_initialPhysicalSize;
QSize m_currentPhysicalSize;
Qt::ScreenOrientation m_nativeOrientation;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index f11a009bca..42318729b1 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -709,12 +709,12 @@ void QQnxWindow::initWindow()
if (window()->parent() && window()->parent()->handle())
setParent(window()->parent()->handle());
- if (shouldMakeFullScreen()) {
+ if (shouldMakeFullScreen())
setGeometryHelper(screen()->geometry());
- QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry());
- } else {
+ else
setGeometryHelper(window()->geometry());
- }
+
+ QWindowSystemInterface::handleGeometryChange(window(), screen()->geometry());
}
void QQnxWindow::createWindowGroup()
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index 8f9ddc2168..1432dfdcd9 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -1040,8 +1040,7 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
QFontEngineMulti *QWindowsFontDatabase::fontEngineMulti(QFontEngine *fontEngine, QChar::Script script)
{
- Q_UNUSED(script)
- return new QWindowsMultiFontEngine(fontEngine, QStringList());
+ return new QWindowsMultiFontEngine(fontEngine, script);
}
QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index c3774064e3..4f3a007bd7 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -1278,35 +1278,14 @@ void QWindowsFontEngine::initFontInfo(const QFontDef &request,
Will probably be superseded by a common Free Type font engine in Qt 5.X.
*/
-
-QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks)
- : QFontEngineMulti(fallbacks.size() + 1),
- fallbackFamilies(fallbacks)
-{
- engines[0] = first;
- first->ref.ref();
- fontDef = engines[0]->fontDef;
- cache_cost = first->cache_cost;
-}
-
-void QWindowsMultiFontEngine::setFallbackFamiliesList(const QStringList &fallbacks)
+QWindowsMultiFontEngine::QWindowsMultiFontEngine(QFontEngine *fe, int script)
+ : QFontEngineMultiQPA(fe, script)
{
- // Original FontEngine to restore after the fill.
- QFontEngine *fe = engines[0];
- fallbackFamilies = fallbacks;
- if (!fallbackFamilies.isEmpty()) {
- engines.fill(0, fallbackFamilies.size() + 1);
- engines[0] = fe;
- } else {
- // Turns out we lied about having any fallback at all.
- fallbackFamilies << fe->fontDef.family;
- engines[1] = fe;
- fe->ref.ref();
- }
}
void QWindowsMultiFontEngine::loadEngine(int at)
{
+ ensureFallbackFamiliesQueried();
Q_ASSERT(at < engines.size());
Q_ASSERT(engines.at(at) == 0);
@@ -1329,7 +1308,7 @@ void QWindowsMultiFontEngine::loadEngine(int at)
data = fe->fontEngineData();
}
- const QString fam = fallbackFamilies.at(at-1);
+ const QString fam = fallbackFamilyAt(at - 1);
memcpy(lf.lfFaceName, fam.utf16(), sizeof(wchar_t) * qMin(fam.length() + 1, 32)); // 32 = Windows hard-coded
#ifndef QT_NO_DIRECTWRITE
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index 7d93484220..7a0803830c 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -53,7 +53,7 @@
// We mean it.
//
-#include <QtGui/private/qfontengine_p.h>
+#include <QtGui/private/qfontengine_qpa_p.h>
#include <QtGui/QImage>
#include <QtCore/QSharedPointer>
@@ -166,15 +166,13 @@ private:
mutable int designAdvancesSize;
};
-class QWindowsMultiFontEngine : public QFontEngineMulti
+
+class QWindowsMultiFontEngine : public QFontEngineMultiQPA
{
public:
- QWindowsMultiFontEngine(QFontEngine *first, const QStringList &fallbacks);
+ explicit QWindowsMultiFontEngine(QFontEngine *fe, int script);
- void setFallbackFamiliesList(const QStringList &fallbacks);
void loadEngine(int at);
-
- QStringList fallbackFamilies;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 274366d4fe..00229a7540 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1365,9 +1365,10 @@ void QWindowsWindow::handleResized(int wParam)
handleGeometryChange();
break;
case SIZE_RESTORED:
- bool fullScreen = isFullScreen_sys();
- if ((m_windowState != Qt::WindowNoState) || fullScreen)
- handleWindowStateChange(fullScreen ? Qt::WindowFullScreen : Qt::WindowNoState);
+ if (isFullScreen_sys())
+ handleWindowStateChange(Qt::WindowFullScreen);
+ else if (m_windowState != Qt::WindowNoState && !testFlag(MaximizeToFullScreen))
+ handleWindowStateChange(Qt::WindowNoState);
handleGeometryChange();
break;
}
@@ -1623,8 +1624,11 @@ void QWindowsWindow::setWindowState_sys(Qt::WindowState newState)
if ((oldState == Qt::WindowMaximized) != (newState == Qt::WindowMaximized)) {
if (visible && !(newState == Qt::WindowMinimized)) {
setFlag(WithinMaximize);
+ if (newState == Qt::WindowFullScreen)
+ setFlag(MaximizeToFullScreen);
ShowWindow(m_data.hwnd, (newState == Qt::WindowMaximized) ? SW_MAXIMIZE : SW_SHOWNOACTIVATE);
clearFlag(WithinMaximize);
+ clearFlag(MaximizeToFullScreen);
}
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index ba0f22bb0a..cb437b76d0 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -153,7 +153,8 @@ public:
AlertState = 0x8000,
Exposed = 0x10000,
WithinCreate = 0x20000,
- WithinMaximize = 0x40000
+ WithinMaximize = 0x40000,
+ MaximizeToFullScreen = 0x80000
};
QWindowsWindow(QWindow *window, const QWindowsWindowData &data);
diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp
index 3da87de708..70bb9469db 100644
--- a/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp
+++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.cpp
@@ -63,7 +63,7 @@ QString QWinRTFontDatabase::fontDir() const
fontDirectory = applicationDirPath + QLatin1String("/fonts");
if (!QFile::exists(fontDirectory)) {
#ifndef Q_OS_WINPHONE
- if (m_fonts.isEmpty())
+ if (m_fontFamilies.isEmpty())
#endif
qWarning("No fonts directory found in application package.");
fontDirectory = applicationDirPath;
@@ -78,6 +78,9 @@ QWinRTFontDatabase::~QWinRTFontDatabase()
{
foreach (IDWriteFontFile *fontFile, m_fonts.keys())
fontFile->Release();
+
+ foreach (IDWriteFontFamily *fontFamily, m_fontFamilies)
+ fontFamily->Release();
}
QFont QWinRTFontDatabase::defaultFont() const
@@ -132,175 +135,196 @@ void QWinRTFontDatabase::populateFontDatabase()
}
QString familyName = QString::fromWCharArray(familyBuffer.data(), familyNameLength);
- int fontCount = fontFamily->GetFontCount();
- for (int j = 0; j < fontCount; ++j) {
- ComPtr<IDWriteFont> font;
- hr = fontFamily->GetFont(j, &font);
- if (FAILED(hr)) {
- qWarning("Unable to get base font: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
+ m_fontFamilies.insert(familyName, fontFamily.Detach());
- ComPtr<IDWriteFontFace> baseFontFace;
- hr = font->CreateFontFace(&baseFontFace);
- if (FAILED(hr)) {
- qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
- ComPtr<IDWriteFontFace1> fontFace;
- hr = baseFontFace.As(&fontFace);
- if (FAILED(hr)) {
- qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
+ registerFontFamily(familyName);
+ }
- // Only try to load true-type fonts
- DWRITE_FONT_FACE_TYPE type = fontFace->GetType();
- if (!(type == DWRITE_FONT_FACE_TYPE_TRUETYPE
- || type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)) {
- continue;
- }
+ QBasicFontDatabase::populateFontDatabase();
+}
- // We can't deal with multi-file fonts
- quint32 fileCount;
- hr = fontFace->GetFiles(&fileCount, NULL);
- if (FAILED(hr)) {
- qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
- if (fileCount != 1) // Should not happen as we only look at TT fonts
- continue;
-
- ComPtr<IDWriteLocalizedStrings> informationalStrings;
- BOOL exists;
- hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER,
- &informationalStrings, &exists);
- if (FAILED(hr)) {
- qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
- QString foundryName;
- if (exists) {
- quint32 length;
- hr = informationalStrings->GetStringLength(0, &length);
+void QWinRTFontDatabase::populateFamily(const QString &familyName)
+{
+ IDWriteFontFamily *fontFamily = m_fontFamilies.value(familyName);
+ if (!fontFamily) {
+ qWarning("The font family %s was not found.", qPrintable(familyName));
+ return;
+ }
+
+ bool fontRegistered = false;
+ const int fontCount = fontFamily->GetFontCount();
+ for (int j = 0; j < fontCount; ++j) {
+ ComPtr<IDWriteFont> font;
+ HRESULT hr = fontFamily->GetFont(j, &font);
+ if (FAILED(hr)) {
+ qWarning("Unable to get font: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+
+ // Skip simulated faces
+ if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
+ continue;
+
+ ComPtr<IDWriteFontFace> baseFontFace;
+ hr = font->CreateFontFace(&baseFontFace);
+ if (FAILED(hr)) {
+ qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+ ComPtr<IDWriteFontFace1> fontFace;
+ hr = baseFontFace.As(&fontFace);
+ if (FAILED(hr)) {
+ qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+
+ // We can't deal with multi-file fonts
+ quint32 fileCount;
+ hr = fontFace->GetFiles(&fileCount, NULL);
+ if (FAILED(hr)) {
+ qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+ if (fileCount != 1)
+ continue;
+
+ ComPtr<IDWriteLocalizedStrings> informationalStrings;
+ BOOL exists;
+ hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER,
+ &informationalStrings, &exists);
+ if (FAILED(hr)) {
+ qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+ QString foundryName;
+ if (exists) {
+ quint32 length;
+ hr = informationalStrings->GetStringLength(0, &length);
+ if (FAILED(hr))
+ qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr)));
+ if (SUCCEEDED(hr)) {
+ QVector<wchar_t> buffer(length + 1);
+ hr = informationalStrings->GetString(0, buffer.data(), buffer.size());
if (FAILED(hr))
- qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr)));
- if (SUCCEEDED(hr)) {
- QVector<wchar_t> buffer(length + 1);
- hr = informationalStrings->GetString(0, buffer.data(), buffer.size());
- if (FAILED(hr))
- qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr)));
- if (SUCCEEDED(hr))
- foundryName = QString::fromWCharArray(buffer.data(), length);
- }
+ qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr)));
+ if (SUCCEEDED(hr))
+ foundryName = QString::fromWCharArray(buffer.data(), length);
}
+ }
- QFont::Weight weight;
- switch (font->GetWeight()) {
- case DWRITE_FONT_WEIGHT_THIN:
- case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
- case DWRITE_FONT_WEIGHT_LIGHT:
- case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
- weight = QFont::Light;
- break;
- default:
- case DWRITE_FONT_WEIGHT_NORMAL:
- case DWRITE_FONT_WEIGHT_MEDIUM:
- weight = QFont::Normal;
- break;
- case DWRITE_FONT_WEIGHT_DEMI_BOLD:
- weight = QFont::DemiBold;
- break;
- case DWRITE_FONT_WEIGHT_BOLD:
- case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
- weight = QFont::Bold;
- break;
- case DWRITE_FONT_WEIGHT_BLACK:
- case DWRITE_FONT_WEIGHT_EXTRA_BLACK:
- weight = QFont::Black;
- break;
- }
+ QFont::Weight weight;
+ switch (font->GetWeight()) {
+ case DWRITE_FONT_WEIGHT_THIN:
+ case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
+ case DWRITE_FONT_WEIGHT_LIGHT:
+ case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
+ weight = QFont::Light;
+ break;
+ default:
+ case DWRITE_FONT_WEIGHT_NORMAL:
+ case DWRITE_FONT_WEIGHT_MEDIUM:
+ weight = QFont::Normal;
+ break;
+ case DWRITE_FONT_WEIGHT_DEMI_BOLD:
+ weight = QFont::DemiBold;
+ break;
+ case DWRITE_FONT_WEIGHT_BOLD:
+ case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
+ weight = QFont::Bold;
+ break;
+ case DWRITE_FONT_WEIGHT_BLACK:
+ case DWRITE_FONT_WEIGHT_EXTRA_BLACK:
+ weight = QFont::Black;
+ break;
+ }
- QFont::Style style;
- switch (font->GetStyle()) {
- default:
- case DWRITE_FONT_STYLE_NORMAL:
- style = QFont::StyleNormal;
- break;
- case DWRITE_FONT_STYLE_OBLIQUE:
- style = QFont::StyleOblique;
- break;
- case DWRITE_FONT_STYLE_ITALIC:
- style = QFont::StyleItalic;
- break;
- }
+ QFont::Style style;
+ switch (font->GetStyle()) {
+ default:
+ case DWRITE_FONT_STYLE_NORMAL:
+ style = QFont::StyleNormal;
+ break;
+ case DWRITE_FONT_STYLE_OBLIQUE:
+ style = QFont::StyleOblique;
+ break;
+ case DWRITE_FONT_STYLE_ITALIC:
+ style = QFont::StyleItalic;
+ break;
+ }
- QFont::Stretch stretch;
- switch (font->GetStretch()) {
- default:
- case DWRITE_FONT_STRETCH_UNDEFINED:
- case DWRITE_FONT_STRETCH_NORMAL:
- stretch = QFont::Unstretched;
- break;
- case DWRITE_FONT_STRETCH_ULTRA_CONDENSED:
- stretch = QFont::UltraCondensed;
- break;
- case DWRITE_FONT_STRETCH_EXTRA_CONDENSED:
- stretch = QFont::ExtraCondensed;
- break;
- case DWRITE_FONT_STRETCH_CONDENSED:
- stretch = QFont::Condensed;
- break;
- case DWRITE_FONT_STRETCH_SEMI_CONDENSED:
- stretch = QFont::SemiCondensed;
- break;
- case DWRITE_FONT_STRETCH_SEMI_EXPANDED:
- stretch = QFont::SemiExpanded;
- break;
- case DWRITE_FONT_STRETCH_EXPANDED:
- stretch = QFont::Expanded;
- break;
- case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:
- stretch = QFont::ExtraExpanded;
- break;
- case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:
- stretch = QFont::UltraExpanded;
- break;
- }
+ QFont::Stretch stretch;
+ switch (font->GetStretch()) {
+ default:
+ case DWRITE_FONT_STRETCH_UNDEFINED:
+ case DWRITE_FONT_STRETCH_NORMAL:
+ stretch = QFont::Unstretched;
+ break;
+ case DWRITE_FONT_STRETCH_ULTRA_CONDENSED:
+ stretch = QFont::UltraCondensed;
+ break;
+ case DWRITE_FONT_STRETCH_EXTRA_CONDENSED:
+ stretch = QFont::ExtraCondensed;
+ break;
+ case DWRITE_FONT_STRETCH_CONDENSED:
+ stretch = QFont::Condensed;
+ break;
+ case DWRITE_FONT_STRETCH_SEMI_CONDENSED:
+ stretch = QFont::SemiCondensed;
+ break;
+ case DWRITE_FONT_STRETCH_SEMI_EXPANDED:
+ stretch = QFont::SemiExpanded;
+ break;
+ case DWRITE_FONT_STRETCH_EXPANDED:
+ stretch = QFont::Expanded;
+ break;
+ case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:
+ stretch = QFont::ExtraExpanded;
+ break;
+ case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:
+ stretch = QFont::UltraExpanded;
+ break;
+ }
- const bool fixedPitch = fontFace->IsMonospacedFont();
+ const bool fixedPitch = fontFace->IsMonospacedFont();
- quint32 unicodeRange[4];
- quint32 actualRangeCount;
- hr = fontFace->GetUnicodeRanges(
- 2, reinterpret_cast<DWRITE_UNICODE_RANGE *>(unicodeRange), &actualRangeCount);
- if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices
- qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
- quint32 codePageRange[2] = { 0, 0 };
- QSupportedWritingSystems writingSystems =
- QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
-
- IDWriteFontFile *fontFile;
- hr = fontFace->GetFiles(&fileCount, &fontFile);
- if (FAILED(hr)) {
- qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr)));
- continue;
- }
+ quint32 unicodeRange[4];
+ quint32 actualRangeCount;
+ hr = fontFace->GetUnicodeRanges(
+ 2, reinterpret_cast<DWRITE_UNICODE_RANGE *>(unicodeRange), &actualRangeCount);
+ if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices
+ qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr)));
+ continue;
+ }
+ quint32 codePageRange[2] = { 0, 0 };
+ QSupportedWritingSystems writingSystems =
+ QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
- FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() };
- m_fonts.insert(fontFile, description);
- registerFont(familyName, QString(), foundryName, weight, style, stretch,
- true, true, 0, fixedPitch, writingSystems, fontFile);
+ IDWriteFontFile *fontFile;
+ hr = fontFace->GetFiles(&fileCount, &fontFile);
+ if (FAILED(hr)) {
+ qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr)));
+ continue;
}
+
+ FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() };
+ m_fonts.insert(fontFile, description);
+ registerFont(familyName, QString(), foundryName, weight, style, stretch,
+ true, true, 0, fixedPitch, writingSystems, fontFile);
+ fontRegistered = true;
}
- QBasicFontDatabase::populateFontDatabase();
+ // Always populate something to avoid an assert
+ if (!fontRegistered) {
+ registerFont(familyName, QString(), QString(), QFont::Normal, QFont::StyleNormal,
+ QFont::Unstretched, false, false, 0, false, QSupportedWritingSystems(), 0);
+ }
}
QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
+ if (!handle) // Happens if a font family population failed
+ return 0;
+
IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle);
if (!m_fonts.contains(fontFile))
return QBasicFontDatabase::fontEngine(fontDef, handle);
@@ -361,6 +385,9 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl
void QWinRTFontDatabase::releaseHandle(void *handle)
{
+ if (!handle)
+ return;
+
IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle);
if (m_fonts.contains(fontFile)) {
m_fonts.remove(fontFile);
diff --git a/src/plugins/platforms/winrt/qwinrtfontdatabase.h b/src/plugins/platforms/winrt/qwinrtfontdatabase.h
index 6f194a10cc..b318a95502 100644
--- a/src/plugins/platforms/winrt/qwinrtfontdatabase.h
+++ b/src/plugins/platforms/winrt/qwinrtfontdatabase.h
@@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE
#ifndef Q_OS_WINPHONE
struct IDWriteFontFile;
+struct IDWriteFontFamily;
struct FontDescription
{
@@ -64,10 +65,12 @@ public:
~QWinRTFontDatabase();
QFont defaultFont() const Q_DECL_OVERRIDE;
void populateFontDatabase() Q_DECL_OVERRIDE;
+ void populateFamily(const QString &familyName) Q_DECL_OVERRIDE;
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE;
void releaseHandle(void *handle) Q_DECL_OVERRIDE;
private:
QHash<IDWriteFontFile *, FontDescription> m_fonts;
+ QHash<QString, IDWriteFontFamily *> m_fontFamilies;
#endif // !Q_OS_WINPHONE
};
diff --git a/src/plugins/platforms/winrt/qwinrtintegration.cpp b/src/plugins/platforms/winrt/qwinrtintegration.cpp
index be82390723..b3a2cafa2e 100644
--- a/src/plugins/platforms/winrt/qwinrtintegration.cpp
+++ b/src/plugins/platforms/winrt/qwinrtintegration.cpp
@@ -124,6 +124,8 @@ bool QWinRTIntegration::hasCapability(QPlatformIntegration::Capability cap) cons
case OpenGL:
case ApplicationState:
return true;
+ case NonFullScreenWindows:
+ return false;
default:
return QPlatformIntegration::hasCapability(cap);
}
diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro
index 306bbc8174..60c87bb61a 100644
--- a/src/plugins/platforms/winrt/winrt.pro
+++ b/src/plugins/platforms/winrt/winrt.pro
@@ -1,6 +1,15 @@
TARGET = qwinrt
CONFIG -= precompile_header
+# For Windows Phone 8 we have to deploy fonts together with the application as DirectWrite
+# is not supported here.
+# TODO: Add a condition/remove this block if Windows Phone 8.1 supports DirectWrite
+winphone {
+ fonts.path = $$[QT_INSTALL_LIBS]/fonts
+ fonts.files = $$QT_SOURCE_TREE/lib/fonts/DejaVu*.ttf
+ INSTALLS += fonts
+}
+
PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin
load(qt_plugin)
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index a68ae8cf71..66b8401ea2 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -185,8 +185,12 @@ void QXcbConnection::updateScreens()
siblings << screen;
activeScreens << screen;
++screenNumber;
- if (!primaryScreen && primary) {
- if (m_primaryScreen == xcbScreenNumber && (primary->output == XCB_NONE || outputs[i] == primary->output)) {
+ // There can be multiple outputs per screen, use either
+ // the first or an exact match. An exact match isn't
+ // always available if primary->output is XCB_NONE
+ // or currently disconnected output.
+ if (m_primaryScreen == xcbScreenNumber) {
+ if (!primaryScreen || (primary && outputs[i] == primary->output)) {
primaryScreen = screen;
siblings.prepend(siblings.takeLast());
#ifdef Q_XCB_DEBUG
@@ -766,6 +770,7 @@ namespace {
xcb_timestamp_t time;
uint8_t deviceID;
} any;
+ xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
xcb_xkb_map_notify_event_t map_notify;
xcb_xkb_state_notify_event_t state_notify;
} _xkb_event;
@@ -796,15 +801,11 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_EXPOSE:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
case XCB_BUTTON_PRESS:
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_button_press_event_t *)event)->state);
-#endif
handleButtonPress(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
case XCB_BUTTON_RELEASE:
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_button_release_event_t *)event)->state);
-#endif
handleButtonRelease(event);
HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
case XCB_MOTION_NOTIFY:
@@ -812,9 +813,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
xcb_motion_notify_event_t *mev = (xcb_motion_notify_event_t *)event;
qDebug("xcb: moved mouse to %4d, %4d; button state %X", mev->event_x, mev->event_y, static_cast<unsigned int>(m_buttons));
}
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_motion_notify_event_t *)event)->state);
-#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
case XCB_CONFIGURE_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
@@ -830,29 +829,21 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
case XCB_ENTER_NOTIFY:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
case XCB_LEAVE_NOTIFY:
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state);
-#endif
HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
case XCB_FOCUS_IN:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
case XCB_FOCUS_OUT:
HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
case XCB_KEY_PRESS:
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_key_press_event_t *)event)->state);
-#endif
HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
case XCB_KEY_RELEASE:
-#ifdef QT_NO_XKB
m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state);
-#endif
HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
-#ifdef QT_NO_XKB
case XCB_MAPPING_NOTIFY:
m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
break;
-#endif
case XCB_SELECTION_REQUEST:
{
xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
@@ -920,6 +911,8 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
_xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event);
if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) {
switch (xkb_event->any.xkbType) {
+ // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap
+ // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations.
case XCB_XKB_STATE_NOTIFY:
m_keyboard->updateXKBState(&xkb_event->state_notify);
handled = true;
@@ -928,6 +921,12 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
m_keyboard->handleMappingNotifyEvent(&xkb_event->map_notify);
handled = true;
break;
+ case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
+ xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify;
+ if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
+ m_keyboard->updateKeymap();
+ break;
+ }
default:
break;
}
@@ -1661,6 +1660,7 @@ void QXcbConnection::initializeXKB()
#ifndef QT_NO_XKB
const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xkb_id);
if (!reply || !reply->present) {
+ qWarning() << "Qt: XKEYBOARD extension not present on the X server.";
xkb_first_event = 0;
return;
}
@@ -1670,14 +1670,14 @@ void QXcbConnection::initializeXKB()
xcb_xkb_use_extension_cookie_t xkb_query_cookie;
xcb_xkb_use_extension_reply_t *xkb_query;
- xkb_query_cookie = xcb_xkb_use_extension(c, XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION);
+ xkb_query_cookie = xcb_xkb_use_extension(c, XKB_X11_MIN_MAJOR_XKB_VERSION, XKB_X11_MIN_MINOR_XKB_VERSION);
xkb_query = xcb_xkb_use_extension_reply(c, xkb_query_cookie, 0);
if (!xkb_query) {
qWarning("Qt: Failed to initialize XKB extension");
return;
} else if (!xkb_query->supported) {
- qWarning("Qt: Unsupported XKB version (want %d %d, has %d %d)",
+ qWarning("Qt: Unsupported XKB version (We want %d %d, but X server has %d %d)",
XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
xkb_query->serverMajor, xkb_query->serverMinor);
free(xkb_query);
@@ -1687,25 +1687,28 @@ void QXcbConnection::initializeXKB()
has_xkb = true;
free(xkb_query);
- uint affectMap, map;
- affectMap = map = XCB_XKB_MAP_PART_KEY_TYPES |
- XCB_XKB_MAP_PART_KEY_SYMS |
- XCB_XKB_MAP_PART_MODIFIER_MAP |
- XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
- XCB_XKB_MAP_PART_KEY_ACTIONS |
- XCB_XKB_MAP_PART_KEY_BEHAVIORS |
- XCB_XKB_MAP_PART_VIRTUAL_MODS |
- XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP;
-
- // Xkb events are reported to all interested clients without regard
+ const uint16_t required_map_parts = (XCB_XKB_MAP_PART_KEY_TYPES |
+ XCB_XKB_MAP_PART_KEY_SYMS |
+ XCB_XKB_MAP_PART_MODIFIER_MAP |
+ XCB_XKB_MAP_PART_EXPLICIT_COMPONENTS |
+ XCB_XKB_MAP_PART_KEY_ACTIONS |
+ XCB_XKB_MAP_PART_KEY_BEHAVIORS |
+ XCB_XKB_MAP_PART_VIRTUAL_MODS |
+ XCB_XKB_MAP_PART_VIRTUAL_MOD_MAP);
+
+ const uint16_t required_events = (XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
+ XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
+ XCB_XKB_EVENT_TYPE_STATE_NOTIFY);
+
+ // XKB events are reported to all interested clients without regard
// to the current keyboard input focus or grab state
xcb_void_cookie_t select = xcb_xkb_select_events_checked(c,
XCB_XKB_ID_USE_CORE_KBD,
- XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
+ required_events,
0,
- XCB_XKB_EVENT_TYPE_STATE_NOTIFY | XCB_XKB_EVENT_TYPE_MAP_NOTIFY,
- affectMap,
- map,
+ required_events,
+ required_map_parts,
+ required_map_parts,
0);
xcb_generic_error_t *error = xcb_request_check(c, select);
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 71f5ce13fb..a994c51c7d 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -54,7 +54,7 @@
#include <qpa/qwindowsysteminterface.h>
// This is needed to make Qt compile together with XKB. xkb.h is using a variable
-// which is called 'explicit', this is a reserved keyword in c++ */
+// which is called 'explicit', this is a reserved keyword in c++
#ifndef QT_NO_XKB
#define explicit dont_use_cxx_explicit
#include <xcb/xkb.h>
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index 0a52640c9a..92b24f4722 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -38,20 +38,22 @@
** $QT_END_LICENSE$
**
****************************************************************************/
-
#include "qxcbkeyboard.h"
#include "qxcbwindow.h"
#include "qxcbscreen.h"
-#include <X11/keysym.h>
+
#include <qpa/qwindowsysteminterface.h>
+#include <qpa/qplatforminputcontext.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformcursor.h>
+
#include <QtCore/QTextCodec>
#include <QtCore/QMetaMethod>
+#include <QtCore/QDir>
#include <private/qguiapplication_p.h>
-#include <stdio.h>
-#include <qpa/qplatforminputcontext.h>
-#include <qpa/qplatformintegration.h>
-#include <qpa/qplatformcursor.h>
+#include <stdio.h>
+#include <X11/keysym.h>
#ifndef XK_ISO_Left_Tab
#define XK_ISO_Left_Tab 0xFE20
@@ -619,6 +621,12 @@ void QXcbKeyboard::readXKBConfig()
char *xkb_config = (char *)xcb_get_property_value(config_reply);
int length = xcb_get_property_value_length(config_reply);
+ // on old X servers xkb_config can be 0 even if config_reply indicates a succesfull read
+ if (!xkb_config || length == 0)
+ return;
+ // ### TODO some X servers don't set _XKB_RULES_NAMES at all, in these cases it is filled
+ // with gibberish, we would need to do some kind of sanity check
+
char *names[5] = { 0, 0, 0, 0, 0 };
char *p = xkb_config, *end = p + length;
int i = 0;
@@ -655,78 +663,97 @@ void QXcbKeyboard::clearXKBConfig()
memset(&xkb_names, 0, sizeof(xkb_names));
}
+void QXcbKeyboard::printKeymapError(const QString &error) const
+{
+ qWarning() << "Qt: " << error;
+ // check if XKB config root is a valid path
+ const QDir xkbRoot = qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")
+ ? QString::fromLocal8Bit(qgetenv("QT_XKB_CONFIG_ROOT"))
+ : DFLT_XKB_CONFIG_ROOT;
+ if (!xkbRoot.exists() || xkbRoot.dirName() != "xkb") {
+ qWarning() << "Set QT_XKB_CONFIG_ROOT to provide a valid XKB configuration data path, current search paths: "
+ << xkbRoot.path() << ". Use ':' as separator to provide several search paths.";
+ return;
+ }
+ qWarning() << "_XKB_RULES_NAMES property contains:" << "\nrules : " << xkb_names.rules <<
+ "\nmodel : " << xkb_names.model << "\nlayout : " << xkb_names.layout <<
+ "\nvariant : " << xkb_names.variant << "\noptions : " << xkb_names.options <<
+ "\nIf this looks like a valid keyboard layout information then you might need to "
+ "update XKB configuration data on the system (http://cgit.freedesktop.org/xkeyboard-config/).";
+}
+
void QXcbKeyboard::updateKeymap()
{
m_config = true;
+ // set xkb context object
if (!xkb_context) {
- xkb_context = xkb_context_new((xkb_context_flags)0);
+ if (qEnvironmentVariableIsSet("QT_XKB_CONFIG_ROOT")) {
+ xkb_context = xkb_context_new((xkb_context_flags)XKB_CONTEXT_NO_DEFAULT_INCLUDES);
+ QList<QByteArray> xkbRootList = QByteArray(qgetenv("QT_XKB_CONFIG_ROOT")).split(':');
+ foreach (QByteArray xkbRoot, xkbRootList)
+ xkb_context_include_path_append(xkb_context, xkbRoot.constData());
+ } else {
+ xkb_context = xkb_context_new((xkb_context_flags)0);
+ }
if (!xkb_context) {
- qWarning("Qt: Failed to create XKB context");
+ printKeymapError("Failed to create XKB context!");
m_config = false;
return;
}
+ // log only critical errors, we do our own error logging from printKeymapError()
+ xkb_context_set_log_level(xkb_context, (xkb_log_level)XKB_LOG_LEVEL_CRITICAL);
}
- readXKBConfig();
- // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names
- if (xkb_keymap)
- xkb_keymap_unref(xkb_keymap);
-
- xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
+ // update xkb keymap object
+ xkb_keymap_unref(xkb_keymap);
+ xkb_keymap = 0;
+ struct xkb_state *new_state = 0;
+#ifndef QT_NO_XKB
+ if (connection()->hasXKB()) {
+ xkb_keymap = xkb_x11_keymap_new_from_device(xkb_context, xcb_connection(), core_device_id, (xkb_keymap_compile_flags)0);
+ if (xkb_keymap) {
+ // Create a new keyboard state object for a keymap
+ new_state = xkb_x11_state_new_from_device(xkb_keymap, xcb_connection(), core_device_id);
+ }
+ }
+#endif
if (!xkb_keymap) {
- qWarning("Qt: Failed to compile a keymap");
- m_config = false;
- return;
+ // Compile a keymap from RMLVO (rules, models, layouts, variants and options) names
+ readXKBConfig();
+ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
+ if (!xkb_keymap) {
+ // last fallback is to used hard-coded keymap name, see DEFAULT_XKB_* in xkbcommon.pri
+ qWarning() << "Qt: Could not determine keyboard configuration data"
+ " from X server, will use hard-coded keymap configuration.";
+ clearXKBConfig();
+ xkb_keymap = xkb_keymap_new_from_names(xkb_context, &xkb_names, (xkb_keymap_compile_flags)0);
+ }
+ if (xkb_keymap) {
+ new_state = xkb_state_new(xkb_keymap);
+ } else {
+ // failed to compile from RMLVO, give a verbose error message
+ printKeymapError("Qt: Failed to compile a keymap!");
+ m_config = false;
+ return;
+ }
+
}
- // Create a new keyboard state object for a keymap
- struct xkb_state *new_state = xkb_state_new(xkb_keymap);
if (!new_state) {
- qWarning("Qt: Failed to create a new keyboard state");
+ qWarning("Qt: Failed to create xkb state!");
m_config = false;
return;
}
-
- if (xkb_state) {
- xkb_state_unref(xkb_state);
- xkb_state = new_state;
- } else {
- xkb_state = new_state;
-#ifndef QT_NO_XKB
- // get initial state from the X server (and keep it up-to-date at all times)
- xcb_xkb_get_state_cookie_t state;
- xcb_xkb_get_state_reply_t *init_state;
-
- xcb_connection_t *c = xcb_connection();
- state = xcb_xkb_get_state(c, XCB_XKB_ID_USE_CORE_KBD);
- init_state = xcb_xkb_get_state_reply(c, state, 0);
- if (!init_state) {
- qWarning("Qt: couldn't retrieve an initial keyboard state");
- return;
- }
- /* The xkb keyboard state is comprised of the state of all keyboard modifiers,
- the keyboard group, and the state of the pointer buttons */
- xkb_state_update_mask(xkb_state,
- init_state->baseMods,
- init_state->latchedMods,
- init_state->lockedMods,
- init_state->baseGroup,
- init_state->latchedGroup,
- init_state->lockedGroup);
- free(init_state);
-#else
+ // update xkb state object
+ xkb_state_unref(xkb_state);
+ xkb_state = new_state;
+ if (!connection()->hasXKB())
updateXKBMods();
-#endif
- }
}
#ifndef QT_NO_XKB
void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
{
- if (!m_config)
- return;
-
- if (connection()->hasXKB()) {
-
+ if (m_config && connection()->hasXKB()) {
const xkb_state_component newState
= xkb_state_update_mask(xkb_state,
state->baseMods,
@@ -741,35 +768,34 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state)
}
}
}
+#endif
-#else
void QXcbKeyboard::updateXKBStateFromCore(quint16 state)
{
- if (!m_config)
- return;
+ if (m_config && !connection()->hasXKB()) {
+ const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
+ const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
+ const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
+ const quint32 xkbMask = xkbModMask(state);
+
+ const quint32 latched = modsLatched & xkbMask;
+ const quint32 locked = modsLocked & xkbMask;
+ quint32 depressed = modsDepressed & xkbMask;
+ // set modifiers in depressed if they don't appear in any of the final masks
+ depressed |= ~(depressed | latched | locked) & xkbMask;
- const quint32 modsDepressed = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_DEPRESSED);
- const quint32 modsLatched = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED);
- const quint32 modsLocked = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED);
- const quint32 xkbMask = xkbModMask(state);
-
- const quint32 latched = modsLatched & xkbMask;
- const quint32 locked = modsLocked & xkbMask;
- quint32 depressed = modsDepressed & xkbMask;
- // set modifiers in depressed if they don't appear in any of the final masks
- depressed |= ~(depressed | latched | locked) & xkbMask;
-
- const xkb_state_component newState
- = xkb_state_update_mask(xkb_state,
- depressed,
- latched,
- locked,
- 0,
- 0,
- (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
-
- if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
- //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ const xkb_state_component newState
+ = xkb_state_update_mask(xkb_state,
+ depressed,
+ latched,
+ locked,
+ 0,
+ 0,
+ (state >> 13) & 3); // bits 13 and 14 report the state keyboard group
+
+ if ((newState & XKB_STATE_LAYOUT_EFFECTIVE) == XKB_STATE_LAYOUT_EFFECTIVE) {
+ //qWarning("TODO: Support KeyboardLayoutChange on QPA (QTBUG-27681)");
+ }
}
}
@@ -799,16 +825,15 @@ quint32 QXcbKeyboard::xkbModMask(quint16 state)
void QXcbKeyboard::updateXKBMods()
{
- xkb_mods.shift = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT);
- xkb_mods.lock = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS);
- xkb_mods.control = xkb_map_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL);
- xkb_mods.mod1 = xkb_map_mod_get_index(xkb_keymap, "Mod1");
- xkb_mods.mod2 = xkb_map_mod_get_index(xkb_keymap, "Mod2");
- xkb_mods.mod3 = xkb_map_mod_get_index(xkb_keymap, "Mod3");
- xkb_mods.mod4 = xkb_map_mod_get_index(xkb_keymap, "Mod4");
- xkb_mods.mod5 = xkb_map_mod_get_index(xkb_keymap, "Mod5");
+ xkb_mods.shift = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_SHIFT);
+ xkb_mods.lock = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CAPS);
+ xkb_mods.control = xkb_keymap_mod_get_index(xkb_keymap, XKB_MOD_NAME_CTRL);
+ xkb_mods.mod1 = xkb_keymap_mod_get_index(xkb_keymap, "Mod1");
+ xkb_mods.mod2 = xkb_keymap_mod_get_index(xkb_keymap, "Mod2");
+ xkb_mods.mod3 = xkb_keymap_mod_get_index(xkb_keymap, "Mod3");
+ xkb_mods.mod4 = xkb_keymap_mod_get_index(xkb_keymap, "Mod4");
+ xkb_mods.mod5 = xkb_keymap_mod_get_index(xkb_keymap, "Mod5");
}
-#endif
QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
{
@@ -893,10 +918,8 @@ QList<int> QXcbKeyboard::possibleKeys(const QKeyEvent *event) const
result += (qtKey + mods);
}
}
- if (kb_state)
- xkb_state_unref(kb_state);
- if (fallback_keymap)
- xkb_keymap_unref(fallback_keymap);
+ xkb_state_unref(kb_state);
+ xkb_keymap_unref(fallback_keymap);
return result;
}
@@ -963,58 +986,41 @@ QXcbKeyboard::QXcbKeyboard(QXcbConnection *connection)
, xkb_context(0)
, xkb_keymap(0)
, xkb_state(0)
-#ifndef QT_NO_XKB
, core_device_id(0)
-#endif
{
memset(&xkb_names, 0, sizeof(xkb_names));
- updateKeymap();
#ifndef QT_NO_XKB
if (connection->hasXKB()) {
-
updateVModMapping();
updateVModToRModMapping();
-
- // get the core keyboard id
- xcb_xkb_get_device_info_cookie_t device_id_cookie;
- xcb_xkb_get_device_info_reply_t *device_id;
-
- device_id_cookie = xcb_xkb_get_device_info(xcb_connection(),
- XCB_XKB_ID_USE_CORE_KBD,
- 0, 0, 0, 0, 0, 0);
-
- device_id = xcb_xkb_get_device_info_reply(xcb_connection(), device_id_cookie, 0);
- if (!device_id) {
+ core_device_id = xkb_x11_get_core_keyboard_device_id(xcb_connection());
+ if (core_device_id == -1) {
qWarning("Qt: couldn't get core keyboard device info");
return;
}
-
- core_device_id = device_id->deviceID;
- free(device_id);
+ } else {
+#endif
+ m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
+ updateModifiers();
+#ifndef QT_NO_XKB
}
-#else
- m_key_symbols = xcb_key_symbols_alloc(xcb_connection());
- updateModifiers();
#endif
+ updateKeymap();
}
QXcbKeyboard::~QXcbKeyboard()
{
- if (xkb_state)
- xkb_state_unref(xkb_state);
- if (xkb_keymap)
- xkb_keymap_unref(xkb_keymap);
- if (xkb_context)
- xkb_context_unref(xkb_context);
-#ifdef QT_NO_XKB
- xcb_key_symbols_free(m_key_symbols);
-#endif
+ xkb_state_unref(xkb_state);
+ xkb_keymap_unref(xkb_keymap);
+ xkb_context_unref(xkb_context);
+ if (!connection()->hasXKB())
+ xcb_key_symbols_free(m_key_symbols);
clearXKBConfig();
}
-#ifndef QT_NO_XKB
void QXcbKeyboard::updateVModMapping()
{
+#ifndef QT_NO_XKB
xcb_xkb_get_names_cookie_t names_cookie;
xcb_xkb_get_names_reply_t *name_reply;
xcb_xkb_get_names_value_list_t names_list;
@@ -1078,10 +1084,12 @@ void QXcbKeyboard::updateVModMapping()
}
free(name_reply);
+#endif
}
void QXcbKeyboard::updateVModToRModMapping()
{
+#ifndef QT_NO_XKB
xcb_xkb_get_map_cookie_t map_cookie;
xcb_xkb_get_map_reply_t *map_reply;
xcb_xkb_get_map_map_t map;
@@ -1144,8 +1152,9 @@ void QXcbKeyboard::updateVModToRModMapping()
free(map_reply);
resolveMaskConflicts();
+#endif
}
-#else
+
void QXcbKeyboard::updateModifiers()
{
// The core protocol does not provide a convenient way to determine the mapping
@@ -1209,7 +1218,6 @@ void QXcbKeyboard::updateModifiers()
free(modMapReply);
resolveMaskConflicts();
}
-#endif
void QXcbKeyboard::resolveMaskConflicts()
{
@@ -1292,17 +1300,9 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
if (!m_config)
return;
- // It is crucial the order of xkb_state_key_get_one_sym &
- // xkb_state_update_key operations is not reversed!
+
+ // It is crucial the order of xkb_state_key_get_one_sym & xkb_state_update_key operations is not reversed!
xcb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, code);
-#ifdef QT_NO_XKB
- enum xkb_key_direction direction;
- if (type == QEvent::KeyPress)
- direction = XKB_KEY_DOWN;
- else
- direction = XKB_KEY_UP;
- xkb_state_update_key(xkb_state, code, direction);
-#endif
QPlatformInputContext *inputContext = QGuiApplicationPrivate::platformIntegration()->inputContext();
QMetaMethod method;
@@ -1422,17 +1422,14 @@ void QXcbKeyboard::handleKeyReleaseEvent(QXcbWindowEventListener *eventListener,
void QXcbKeyboard::handleMappingNotifyEvent(const void *event)
{
updateKeymap();
-#ifdef QT_NO_XKB
- void *ev = const_cast<void *>(event);
- xcb_refresh_keyboard_mapping(m_key_symbols, static_cast<xcb_mapping_notify_event_t *>(ev));
- updateModifiers();
-#else
- Q_UNUSED(event)
if (connection()->hasXKB()) {
updateVModMapping();
updateVModToRModMapping();
+ } else {
+ void *ev = const_cast<void *>(event);
+ xcb_refresh_keyboard_mapping(m_key_symbols, static_cast<xcb_mapping_notify_event_t *>(ev));
+ updateModifiers();
}
-#endif
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h
index 0256602782..36ce1ea2f0 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.h
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.h
@@ -44,11 +44,15 @@
#include "qxcbobject.h"
-#ifdef QT_NO_XKB
#include <xcb/xcb_keysyms.h>
-#endif
#include <xkbcommon/xkbcommon.h>
+#ifndef QT_NO_XKB
+// note: extern won't be needed from libxkbcommon 0.4.1 and above
+extern "C" {
+#include <xkbcommon/xkbcommon-x11.h>
+}
+#endif
#include <QEvent>
@@ -65,41 +69,38 @@ public:
void handleKeyPressEvent(QXcbWindowEventListener *eventListener, const xcb_key_press_event_t *event);
void handleKeyReleaseEvent(QXcbWindowEventListener *eventListener, const xcb_key_release_event_t *event);
-
void handleMappingNotifyEvent(const void *event);
Qt::KeyboardModifiers translateModifiers(int s) const;
-
void updateKeymap();
QList<int> possibleKeys(const QKeyEvent *e) const;
-#ifdef QT_NO_XKB
- void updateXKBStateFromCore(quint16 state);
+ // when XKEYBOARD not present on the X server
void updateXKBMods();
quint32 xkbModMask(quint16 state);
-#else
- int coreDeviceId() { return core_device_id; }
+ void updateXKBStateFromCore(quint16 state);
+ // when XKEYBOARD is present on the X server
+ int coreDeviceId() const { return core_device_id; }
+#ifndef QT_NO_XKB
void updateXKBState(xcb_xkb_state_notify_event_t *state);
#endif
protected:
void handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycode_t code, quint16 state, xcb_timestamp_t time);
- void resolveMaskConflicts();
+ void resolveMaskConflicts();
QString keysymToUnicode(xcb_keysym_t sym) const;
-
int keysymToQtKey(xcb_keysym_t keysym) const;
int keysymToQtKey(xcb_keysym_t keysym, Qt::KeyboardModifiers &modifiers, QString text) const;
+ void printKeymapError(const QString &error) const;
void readXKBConfig();
void clearXKBConfig();
-
-#ifdef QT_NO_XKB
+ // when XKEYBOARD not present on the X server
void updateModifiers();
-#else
+ // when XKEYBOARD is present on the X server
void updateVModMapping();
void updateVModToRModMapping();
-#endif
private:
bool m_config;
@@ -120,9 +121,8 @@ private:
_mod_masks rmod_masks;
-#ifdef QT_NO_XKB
+ // when XKEYBOARD not present on the X server
xcb_key_symbols_t *m_key_symbols;
-
struct _xkb_mods {
xkb_mod_index_t shift;
xkb_mod_index_t lock;
@@ -133,12 +133,10 @@ private:
xkb_mod_index_t mod4;
xkb_mod_index_t mod5;
};
-
_xkb_mods xkb_mods;
-#else
+ // when XKEYBOARD is present on the X server
_mod_masks vmod_masks;
int core_device_id;
-#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index d890398416..bed6eb59dc 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -1829,21 +1829,21 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
return;
Qt::WindowState newState = Qt::WindowNoState;
- if (event->atom == atom(QXcbAtom::_NET_WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
+ if (event->atom == atom(QXcbAtom::WM_STATE)) { // WM_STATE: Quick check for 'Minimize'.
const xcb_get_property_cookie_t get_cookie =
- xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
- XCB_ATOM_ANY, 0, 1024);
+ xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE),
+ XCB_ATOM_ANY, 0, 1024);
xcb_get_property_reply_t *reply =
xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
- if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::_NET_WM_STATE)) {
+ if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
const quint32 *data = (const quint32 *)xcb_get_property_value(reply);
if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0])
newState = Qt::WindowMinimized;
}
free(reply);
- } // WM_STATE: Quick check for 'Minimize'.
+ }
if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE.
const NetWmStates states = netWmStates();
if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro
index e19bb921e1..9e4e997f55 100644
--- a/src/plugins/platforms/xcb/xcb-plugin.pro
+++ b/src/plugins/platforms/xcb/xcb-plugin.pro
@@ -121,12 +121,8 @@ contains(QT_CONFIG, xcb-qt) {
INCLUDEPATH += $$XCB_DIR/include $$XCB_DIR/sysinclude
LIBS += -lxcb -L$$OUT_PWD/xcb-static -lxcb-static
} else {
- LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape
- contains(DEFINES, QT_NO_XKB) {
- LIBS += -lxcb-keysyms
- } else {
- LIBS += -lxcb-xkb
- }
+ LIBS += -lxcb -lxcb-image -lxcb-icccm -lxcb-sync -lxcb-xfixes -lxcb-shm -lxcb-randr -lxcb-shape -lxcb-keysyms
+ !contains(DEFINES, QT_NO_XKB):LIBS += -lxcb-xkb
}
# libxkbcommon