diff options
author | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-05-02 12:45:40 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-05-02 17:36:45 +0200 |
commit | bdcd86c03e1b5c66dec21746d4d3596eb556b77b (patch) | |
tree | 5d9d24c69a704e5c67ac620ce1c04d2373df0728 /src/plugins/platforms | |
parent | da888ba53904af75c462af9f753191f25840e51f (diff) | |
parent | ccc6efb6e91756451ffd50d51f7f3ae05bc6df0b (diff) |
Merge "Merge remote-tracking branch 'origin/release' into stable" into refs/staging/stable
Diffstat (limited to 'src/plugins/platforms')
26 files changed, 243 insertions, 62 deletions
diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 02fda19d76..e255a49ac7 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org> ** Contact: http://www.qt-project.org/legal ** @@ -338,7 +339,7 @@ static JNINativeMethod methods[] = { QAndroidInputContext::QAndroidInputContext() - : QPlatformInputContext(), m_blockUpdateSelection(false), m_batchEditNestingLevel(0), m_focusObject(0) + : QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false), m_batchEditNestingLevel(0), m_focusObject(0) { QtAndroid::AttachedJNIEnv env; if (!env.jniEnv) @@ -431,9 +432,24 @@ QAndroidInputContext *QAndroidInputContext::androidInputContext() return m_androidInputContext; } +// cursor position getter that also works with editors that have not been updated to the new API +static inline int getAbsoluteCursorPosition(const QSharedPointer<QInputMethodQueryEvent> &query) +{ + QVariant absolutePos = query->value(Qt::ImAbsolutePosition); + return absolutePos.isValid() ? absolutePos.toInt() : query->value(Qt::ImCursorPosition).toInt(); +} + +// position of the start of the current block +static inline int getBlockPosition(const QSharedPointer<QInputMethodQueryEvent> &query) +{ + QVariant absolutePos = query->value(Qt::ImAbsolutePosition); + return absolutePos.isValid() ? absolutePos.toInt() - query->value(Qt::ImCursorPosition).toInt() : 0; +} + void QAndroidInputContext::reset() { clear(); + m_batchEditNestingLevel = 0; if (qGuiApp->focusObject()) QtAndroidInput::resetSoftwareKeyboard(); else @@ -449,13 +465,20 @@ void QAndroidInputContext::updateCursorPosition() { QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); 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(); + const int cursorPos = getAbsoluteCursorPosition(query); 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 + + //Q_ASSERT(m_composingText.isEmpty() == (m_composingTextStart == -1)); + if (m_composingText.isEmpty() != (m_composingTextStart == -1)) + qWarning() << "Input method out of sync" << m_composingText << m_composingTextStart; + + + // Qt's idea of the cursor position is the start of the preedit area, so we have to maintain our own preedit cursor pos + int realCursorPosition = cursorPos; + if (!m_composingText.isEmpty()) + realCursorPosition = m_composingCursor; + QtAndroidInput::updateSelection(realCursorPosition, realCursorPosition, //empty selection + m_composingTextStart, m_composingTextStart + composeLength); // pre-edit text } } @@ -529,6 +552,7 @@ bool QAndroidInputContext::isComposing() const void QAndroidInputContext::clear() { m_composingText.clear(); + m_composingTextStart = -1; m_extractedText.clear(); } @@ -569,8 +593,18 @@ jboolean QAndroidInputContext::endBatchEdit() jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/) { + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); + if (query.isNull()) + return JNI_FALSE; + + + const int cursorPos = getAbsoluteCursorPosition(query); m_composingText = text; - return finishComposingText(); + m_composingTextStart = cursorPos; + m_composingCursor = cursorPos + text.length(); + finishComposingText(); + //### move cursor to newCursorPosition and call updateCursorPosition() + return JNI_TRUE; } jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength) @@ -580,6 +614,7 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right return JNI_TRUE; m_composingText.clear(); + m_composingTextStart = -1; QInputMethodEvent event; event.setCommitString(QString(), -leftLength, leftLength+rightLength); @@ -617,7 +652,9 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/) return res; } -const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/) + + +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 @@ -628,28 +665,37 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex return m_extractedText; 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 blockPos = getBlockPosition(query); + QString blockText = query->value(Qt::ImSurroundingText).toString(); int composeLength = m_composingText.length(); + if (composeLength > 0) { + //Qt doesn't give us the preedit text, so we have to insert it at the correct position + int localComposePos = m_composingTextStart - blockPos; + blockText = blockText.left(localComposePos) + m_composingText + blockText.mid(localComposePos); + } + 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." + // It is documented that we should try to return hintMaxChars + // characters, but that's not what the standard Android controls do, and + // there are input methods out there that (surprise) seem to depend on + // what happens in reality rather than what's documented. + + m_extractedText.text = blockText; + m_extractedText.startOffset = blockPos + localOffset; const QString &selection = query->value(Qt::ImCurrentSelection).toString(); const int selLen = selection.length(); if (selLen) { m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt() - localOffset; m_extractedText.selectionEnd = m_extractedText.selectionStart + selLen; - } else { + } else if (composeLength > 0) { + m_extractedText.selectionStart = m_composingCursor - m_extractedText.startOffset; + m_extractedText.selectionEnd = m_composingCursor - m_extractedText.startOffset; + } else { m_extractedText.selectionStart = cpos - localOffset; m_extractedText.selectionEnd = cpos - localOffset; } @@ -668,6 +714,7 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/) QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/) { + //### the preedit text could theoretically be after the cursor QVariant textAfter = queryFocusObjectThreadSafe(Qt::ImTextAfterCursor, QVariant(length)); if (textAfter.isValid()) { return textAfter.toString().left(length); @@ -703,15 +750,34 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) if (!text.length()) return text; - const int wordLeftPos = cursorPos - length; - return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos) + m_composingText; + //### the preedit text does not need to be immediately before the cursor + if (cursorPos <= length) + return text.left(cursorPos) + m_composingText; + else + return text.mid(cursorPos - length, length) + m_composingText; } +/* + Android docs say that this function should remove the current preedit text + if any, and replace it with the given text. Any selected text should be + removed. The cursor is then moved to newCursorPosition. If > 0, this is + relative to the end of the text - 1; if <= 0, this is relative to the start + of the text. + */ + jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition) { + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); + if (query.isNull()) + return JNI_FALSE; + + const int cursorPos = getAbsoluteCursorPosition(query); if (newCursorPosition > 0) newCursorPosition += text.length() - 1; + m_composingText = text; + m_composingTextStart = text.isEmpty() ? -1 : cursorPos; + m_composingCursor = cursorPos + newCursorPosition; QList<QInputMethodEvent::Attribute> attributes; attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, newCursorPosition, @@ -726,23 +792,26 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur QInputMethodEvent event(m_composingText, attributes); sendInputMethodEvent(&event); - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - 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, -1, -1); - } + updateCursorPosition(); return JNI_TRUE; } // Android docs say: // * start may be after end, same meaning as if swapped -// * this function must not trigger updateSelection +// * this function should not trigger updateSelection // * if start == end then we should stop composing jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) { + // Qt will not include the current preedit text in the query results, and interprets all + // parameters relative to the text excluding the preedit. The simplest solution is therefore to + // tell Qt that we commit the text before we set the new region. This may cause a little flicker, but is + // much more robust than trying to keep the two different world views in sync + + bool wasComposing = !m_composingText.isEmpty(); + if (wasComposing) + finishComposingText(); + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (query.isNull()) return JNI_FALSE; @@ -757,19 +826,23 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) Therefore, the length of the region is end - start */ + int length = end - start; int localPos = query->value(Qt::ImCursorPosition).toInt(); - QVariant absolutePos = query->value(Qt::ImAbsolutePosition); - int blockPosition = absolutePos.isValid() ? absolutePos.toInt() - localPos : 0; + int blockPosition = getBlockPosition(query); int localStart = start - blockPosition; // Qt uses position inside block + int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos; bool updateSelectionWasBlocked = m_blockUpdateSelection; m_blockUpdateSelection = true; QString text = query->value(Qt::ImSurroundingText).toString(); + m_composingText = text.mid(localStart, length); + m_composingTextStart = start; + m_composingCursor = currentCursor; - //in the Qt text controls, the cursor position is the start of the preedit + //in the Qt text controls, the preedit is defined relative to the cursor position int relativeStart = localStart - localPos; QList<QInputMethodEvent::Attribute> attributes; @@ -781,13 +854,22 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) QVariant(underlined))); // Keep the cursor position unchanged (don't move to end of preedit) - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, localPos - localStart, length, QVariant())); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1, QVariant())); QInputMethodEvent event(m_composingText, attributes); event.setCommitString(QString(), relativeStart, length); sendInputMethodEvent(&event); m_blockUpdateSelection = updateSelectionWasBlocked; + +#ifdef QT_DEBUG_ANDROID_IM_PROTOCOL + QSharedPointer<QInputMethodQueryEvent> query2 = focusObjectInputMethodQuery(); + if (!query2.isNull()) { + qDebug() << "Setting. Prev local cpos:" << localPos << "block pos:" <<blockPosition << "comp.start:" << m_composingTextStart << "rel.start:" << relativeStart << "len:" << length << "cpos attr:" << localPos - localStart; + qDebug() << "New cursor pos" << getAbsoluteCursorPosition(query2); + } +#endif + return JNI_TRUE; } @@ -797,18 +879,36 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end) 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; + int blockPosition = getBlockPosition(query); + int localCursorPos = start - blockPosition; QList<QInputMethodEvent::Attribute> attributes; - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, - start - blockPosition, - end - start, - QVariant())); + if (!m_composingText.isEmpty() && start == end) { + // not actually changing the selection; just moving the + // preedit cursor + int localOldPos = query->value(Qt::ImCursorPosition).toInt(); + int pos = localCursorPos - localOldPos; + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1, QVariant())); + + //but we have to tell Qt about the compose text all over again + + // Show compose text underlined + QTextCharFormat underlined; + underlined.setFontUnderline(true); + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, m_composingText.length(), + QVariant(underlined))); + m_composingCursor = start; - QInputMethodEvent event(QString(), attributes); + } else { + // actually changing the selection + attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, + localCursorPos, + end - start, + QVariant())); + } + QInputMethodEvent event(m_composingText, attributes); sendInputMethodEvent(&event); + updateCursorPosition(); return JNI_TRUE; } diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index 3ce141ae15..a467e4849e 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -134,6 +134,8 @@ private slots: private: ExtractedText m_extractedText; QString m_composingText; + int m_composingTextStart; + int m_composingCursor; QMetaObject::Connection m_updateCursorPosConnection; bool m_blockUpdateSelection; int m_batchEditNestingLevel; diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro index a60f4adc28..1f9c0e051d 100644 --- a/src/plugins/platforms/cocoa/cocoa.pro +++ b/src/plugins/platforms/cocoa/cocoa.pro @@ -2,6 +2,7 @@ TARGET = qcocoa PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QCocoaIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) OBJECTIVE_SOURCES += main.mm \ diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 5def64ee0a..60152b56b2 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1375,7 +1375,8 @@ QCocoaNSWindow * QCocoaWindow::createNSWindow() qPlatformWindow:this]; if ((type & Qt::Popup) == Qt::Popup) [window setHasShadow:YES]; - [window setHidesOnDeactivate: NO]; + + [window setHidesOnDeactivate:(type & Qt::Tool) == Qt::Tool]; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 5d20764c87..24a9f6fff0 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -678,9 +678,9 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil; return [super mouseDown:theEvent]; m_sendUpAsRightButton = false; if (m_platformWindow->m_activePopupWindow) { + Qt::WindowType type = m_platformWindow->m_activePopupWindow->type(); QWindowSystemInterface::handleCloseEvent(m_platformWindow->m_activePopupWindow); QWindowSystemInterface::flushWindowSystemEvents(); - Qt::WindowType type = m_platformWindow->m_activePopupWindow->type(); m_platformWindow->m_activePopupWindow = 0; // Consume the mouse event when closing the popup, except for tool tips // were it's expected that the event is processed normally. diff --git a/src/plugins/platforms/direct2d/direct2d.pro b/src/plugins/platforms/direct2d/direct2d.pro index 4f986b57d7..439d31fb56 100644 --- a/src/plugins/platforms/direct2d/direct2d.pro +++ b/src/plugins/platforms/direct2d/direct2d.pro @@ -2,6 +2,7 @@ TARGET = qdirect2d PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWindowsDirect2DIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT *= core-private diff --git a/src/plugins/platforms/directfb/directfb.pro b/src/plugins/platforms/directfb/directfb.pro index ec4a612b52..89d8d42cea 100644 --- a/src/plugins/platforms/directfb/directfb.pro +++ b/src/plugins/platforms/directfb/directfb.pro @@ -2,6 +2,7 @@ TARGET = qdirectfb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QDirectFbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro index 8827f7680c..3ebe05b35e 100644 --- a/src/plugins/platforms/eglfs/eglfs.pro +++ b/src/plugins/platforms/eglfs/eglfs.pro @@ -2,6 +2,7 @@ TARGET = qeglfs PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) SOURCES += $$PWD/main.cpp diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro index b7e074b95a..ffc4ff9b12 100644 --- a/src/plugins/platforms/ios/ios.pro +++ b/src/plugins/platforms/ios/ios.pro @@ -2,6 +2,7 @@ TARGET = qios PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QIOSIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro index 1b3678f13a..baa8778153 100644 --- a/src/plugins/platforms/kms/kms.pro +++ b/src/plugins/platforms/kms/kms.pro @@ -2,6 +2,7 @@ TARGET = qkms PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QKmsIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/linuxfb/linuxfb.pro b/src/plugins/platforms/linuxfb/linuxfb.pro index 9e9f9b29b7..389d45c29c 100644 --- a/src/plugins/platforms/linuxfb/linuxfb.pro +++ b/src/plugins/platforms/linuxfb/linuxfb.pro @@ -2,6 +2,7 @@ TARGET = qlinuxfb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QLinuxFbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/minimal/minimal.pro b/src/plugins/platforms/minimal/minimal.pro index 3131b16232..3ed4d2cdde 100644 --- a/src/plugins/platforms/minimal/minimal.pro +++ b/src/plugins/platforms/minimal/minimal.pro @@ -2,6 +2,7 @@ TARGET = qminimal PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QMinimalIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/minimalegl/minimalegl.pro b/src/plugins/platforms/minimalegl/minimalegl.pro index 00c83eb1ca..e78dcb8bc5 100644 --- a/src/plugins/platforms/minimalegl/minimalegl.pro +++ b/src/plugins/platforms/minimalegl/minimalegl.pro @@ -2,6 +2,7 @@ TARGET = qminimalegl PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QMinimalEglIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro index 5db5e32e65..94eeac6acc 100644 --- a/src/plugins/platforms/offscreen/offscreen.pro +++ b/src/plugins/platforms/offscreen/offscreen.pro @@ -2,6 +2,7 @@ TARGET = qoffscreen PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QOffscreenIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/openwfd/openwf.pro b/src/plugins/platforms/openwfd/openwf.pro index 2dbcb282db..38bac057bd 100644 --- a/src/plugins/platforms/openwfd/openwf.pro +++ b/src/plugins/platforms/openwfd/openwf.pro @@ -2,6 +2,7 @@ TARGET = qopenwf PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QOpenWFDIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/qnx/qnx.pro b/src/plugins/platforms/qnx/qnx.pro index 04c6087cd1..856b7d2abe 100644 --- a/src/plugins/platforms/qnx/qnx.pro +++ b/src/plugins/platforms/qnx/qnx.pro @@ -161,4 +161,5 @@ include (../../../platformsupport/fontdatabases/fontdatabases.pri) PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QQnxIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index de34663286..78bf833526 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -243,7 +243,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co return true; case ThreadedOpenGL: #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - return QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL + return QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL ? QWindowsEGLContext::hasThreadedOpenGLCapability() : true; # else return true; @@ -308,7 +308,7 @@ QPlatformOpenGLContext { qCDebug(lcQpaGl) << __FUNCTION__ << context->format(); #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { if (d->m_staticEGLContext.isNull()) { QWindowsEGLStaticContext *staticContext = QWindowsEGLStaticContext::create(); if (!staticContext) @@ -319,7 +319,7 @@ QPlatformOpenGLContext } #endif #if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { if (d->m_staticOpenGLContext.isNull()) d->m_staticOpenGLContext = QSharedPointer<QOpenGLStaticContext>(QOpenGLStaticContext::create()); diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index 7e15be1d19..06c0122bbb 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -125,7 +125,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour return 0; } #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) { QWindowsEGLContext *windowsEglContext = static_cast<QWindowsEGLContext *>(context->handle()); if (resource == QByteArrayLiteral("eglDisplay")) return windowsEglContext->eglDisplay(); @@ -136,7 +136,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour } #endif // QT_OPENGL_ES_2 || QT_OPENGL_DYNAMIC #if !defined(QT_OPENGL_ES_2) - if (QOpenGLContext::openGLModuleType() == QOpenGLContext::DesktopGL) { + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { QWindowsGLContext *windowsContext = static_cast<QWindowsGLContext *>(context->handle()); if (resource == QByteArrayLiteral("renderingContext")) return windowsContext->renderingContext(); diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index db06525508..c8eaded38d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -880,7 +880,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data) if (aWindow->surfaceType() == QWindow::OpenGLSurface) { setFlag(OpenGLSurface); #if defined(QT_OPENGL_ES_2) || defined(QT_OPENGL_DYNAMIC) - if (QOpenGLContext::openGLModuleType() != QOpenGLContext::DesktopGL) + if (QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL) setFlag(OpenGL_ES2); #endif } diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro index 188bd7917c..cc0373c077 100644 --- a/src/plugins/platforms/windows/windows.pro +++ b/src/plugins/platforms/windows/windows.pro @@ -2,6 +2,7 @@ TARGET = qwindows PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWindowsIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT *= core-private diff --git a/src/plugins/platforms/winrt/winrt.pro b/src/plugins/platforms/winrt/winrt.pro index 60c87bb61a..0122bf9475 100644 --- a/src/plugins/platforms/winrt/winrt.pro +++ b/src/plugins/platforms/winrt/winrt.pro @@ -12,6 +12,7 @@ winphone { PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QWinRTIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index f5f6c712c5..e3b81c2b40 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -1791,6 +1791,19 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, doub return true; } +bool QXcbConnection::xi2GetButtonState(void *event, int buttonNum) +{ + xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event); + unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1]; + + for (int i = 0; i < (xideviceevent->buttons_len * 4); i++) { + if (buttonNum < 8) + return (buttonsMaskAddr[i] & (1 << buttonNum)); + buttonNum -= 8; + } + return false; +} + // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" // - "pad1" and "pad" became "pad0" diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index 13a0280baf..1933b89a19 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -402,6 +402,12 @@ public: #elif defined(XCB_USE_XINPUT2) void xi2Select(xcb_window_t window); #endif +#ifdef XCB_USE_XINPUT21 + bool isUsingXInput21() { return m_xi2Enabled && m_xi2Minor >= 1; } +#else + bool isUsingXInput21() { return false; } +#endif + void sync(); void flush() { xcb_flush(m_connection); } @@ -511,11 +517,12 @@ private: QVector<TabletData> m_tabletData; #endif struct ScrollingDevice { - ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0) { } + ScrollingDevice() : deviceId(0), verticalIndex(0), horizontalIndex(0), orientations(0), legacyOrientations(0) { } int deviceId; int verticalIndex, horizontalIndex; double verticalIncrement, horizontalIncrement; Qt::Orientations orientations; + Qt::Orientations legacyOrientations; QPointF lastScrollPosition; }; void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice); @@ -525,6 +532,7 @@ private: #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO) static bool xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value); static bool xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode); + static bool xi2GetButtonState(void *event, int buttonNum); #endif xcb_connection_t *m_connection; diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index d7b3c75aee..831ccba6f6 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -134,7 +134,6 @@ void QXcbConnection::initializeXInput2() #ifdef XCB_USE_XINPUT21 case XIScrollClass: { XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(devices[i].classes[c]); - scrollingDevice.deviceId = devices[i].deviceid; if (sci->scroll_type == XIScrollTypeVertical) { scrollingDevice.orientations |= Qt::Vertical; scrollingDevice.verticalIndex = sci->number; @@ -147,6 +146,20 @@ void QXcbConnection::initializeXInput2() } break; } + case XIButtonClass: { + XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(devices[i].classes[c]); + for (int i=0; i < bci->num_buttons; ++i) { + const int buttonAtom = qatom(bci->labels[i]); + if (buttonAtom == QXcbAtom::ButtonWheelUp + || buttonAtom == QXcbAtom::ButtonWheelDown) { + scrollingDevice.legacyOrientations |= Qt::Vertical; + } else if (buttonAtom == QXcbAtom::ButtonHorizWheelLeft + || buttonAtom == QXcbAtom::ButtonHorizWheelRight) { + scrollingDevice.legacyOrientations |= Qt::Horizontal; + } + } + break; + } #endif default: break; @@ -170,7 +183,10 @@ void QXcbConnection::initializeXInput2() #endif // QT_NO_TABLETEVENT #ifdef XCB_USE_XINPUT21 - if (scrollingDevice.orientations) { + if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { + scrollingDevice.deviceId = devices[i].deviceid; + // Only use legacy wheel button events when we don't have real scroll valuators. + scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); if (Q_UNLIKELY(debug_xinput_devices)) qDebug() << " it's a scrolling device"; @@ -256,6 +272,7 @@ void QXcbConnection::xi2Select(xcb_window_t window) if (!m_scrollingDevices.isEmpty()) { QVector<XIEventMask> xiEventMask(m_scrollingDevices.size()); bitMask = XI_MotionMask; + bitMask |= XI_ButtonReleaseMask; int i=0; Q_FOREACH (const ScrollingDevice& scrollingDevice, m_scrollingDevices) { xiEventMask[i].deviceid = scrollingDevice.deviceId; @@ -595,6 +612,31 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); } } + } else if (xiEvent->evtype == XI_ButtonRelease) { + xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { + QPoint angleDelta; + if (scrollingDevice.legacyOrientations & Qt::Vertical) { + if (xi2GetButtonState(xiDeviceEvent, 4)) + angleDelta.setY(120); + else if (xi2GetButtonState(xiDeviceEvent, 5)) + angleDelta.setY(-120); + } + if (scrollingDevice.legacyOrientations & Qt::Horizontal) { + if (xi2GetButtonState(xiDeviceEvent, 6)) + angleDelta.setX(120); + if (xi2GetButtonState(xiDeviceEvent, 7)) + angleDelta.setX(-120); + } + if (!angleDelta.isNull()) { + QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); + QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + if (modifiers & Qt::AltModifier) + std::swap(angleDelta.rx(), angleDelta.ry()); + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers); + } + } } #else Q_UNUSED(event); diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index fb9c03b66d..3645b6469a 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -1771,16 +1771,16 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (isWheel) { -#ifndef XCB_USE_XINPUT21 - // Logic borrowed from qapplication_x11.cpp - int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); - bool hor = (((event->detail == 4 || event->detail == 5) - && (modifiers & Qt::AltModifier)) - || (event->detail == 6 || event->detail == 7)); - - QWindowSystemInterface::handleWheelEvent(window(), event->time, - local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); -#endif + if (!connection()->isUsingXInput21()) { + // Logic borrowed from qapplication_x11.cpp + int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); + bool hor = (((event->detail == 4 || event->detail == 5) + && (modifiers & Qt::AltModifier)) + || (event->detail == 6 || event->detail == 7)); + + QWindowSystemInterface::handleWheelEvent(window(), event->time, + local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); + } return; } diff --git a/src/plugins/platforms/xcb/xcb-plugin.pro b/src/plugins/platforms/xcb/xcb-plugin.pro index 9e4e997f55..a52aaa4a2e 100644 --- a/src/plugins/platforms/xcb/xcb-plugin.pro +++ b/src/plugins/platforms/xcb/xcb-plugin.pro @@ -2,6 +2,7 @@ TARGET = qxcb PLUGIN_TYPE = platforms PLUGIN_CLASS_NAME = QXcbIntegrationPlugin +!equals(TARGET, $$QT_DEFAULT_QPA_PLUGIN): PLUGIN_EXTENDS = - load(qt_plugin) QT += core-private gui-private platformsupport-private |