diff options
author | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-07-11 17:17:13 +0200 |
---|---|---|
committer | Alexandru Croitor <alexandru.croitor@qt.io> | 2019-07-11 17:17:51 +0200 |
commit | 4dac45c9ee59ff6586d90d423654da91523ab679 (patch) | |
tree | cd4a4adf2cbc9e77bf86d2d11e71ec66afdf3be4 /src/plugins/platforms | |
parent | 078cd61751aeaa310d35a3d596a21a36004a1a0f (diff) | |
parent | f44850b5c3464cdda0ee9b1ee858d95f3ffaa3e2 (diff) |
Merge remote-tracking branch 'origin/wip/qt6' into wip/cmake
Change-Id: I715b1d743d5f11560e7b3fbeb8fd64a5e5ddb277
Diffstat (limited to 'src/plugins/platforms')
81 files changed, 1052 insertions, 553 deletions
diff --git a/src/plugins/platforms/android/androidjnimenu.cpp b/src/plugins/platforms/android/androidjnimenu.cpp index 6f548aba52..f51a3920b8 100644 --- a/src/plugins/platforms/android/androidjnimenu.cpp +++ b/src/plugins/platforms/android/androidjnimenu.cpp @@ -60,12 +60,12 @@ namespace QtAndroidMenu { static QList<QAndroidPlatformMenu *> pendingContextMenus; static QAndroidPlatformMenu *visibleMenu = 0; - static QMutex visibleMenuMutex(QMutex::Recursive); + static QRecursiveMutex visibleMenuMutex; static QSet<QAndroidPlatformMenuBar *> menuBars; static QAndroidPlatformMenuBar *visibleMenuBar = 0; static QWindow *activeTopLevelWindow = 0; - static QMutex menuBarMutex(QMutex::Recursive); + static QRecursiveMutex menuBarMutex; static jmethodID openContextMenuMethodID = 0; diff --git a/src/plugins/platforms/android/qandroideventdispatcher.cpp b/src/plugins/platforms/android/qandroideventdispatcher.cpp index e12551283f..3a1fb7a6de 100644 --- a/src/plugins/platforms/android/qandroideventdispatcher.cpp +++ b/src/plugins/platforms/android/qandroideventdispatcher.cpp @@ -78,14 +78,14 @@ void QAndroidEventDispatcher::stop() void QAndroidEventDispatcher::goingToStop(bool stop) { - m_goingToStop.store(stop ? 1 : 0); + m_goingToStop.storeRelaxed(stop ? 1 : 0); if (!stop) wakeUp(); } bool QAndroidEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) { - if (m_goingToStop.load()) + if (m_goingToStop.loadRelaxed()) flags |= QEventLoop::ExcludeSocketNotifiers | QEventLoop::X11ExcludeTimers; { diff --git a/src/plugins/platforms/android/qandroideventdispatcher.h b/src/plugins/platforms/android/qandroideventdispatcher.h index e6f903bced..4fdd7af7a5 100644 --- a/src/plugins/platforms/android/qandroideventdispatcher.h +++ b/src/plugins/platforms/android/qandroideventdispatcher.h @@ -68,7 +68,7 @@ class QAndroidEventDispatcherStopper { public: static QAndroidEventDispatcherStopper *instance(); - static bool stopped() {return !instance()->m_started.load(); } + static bool stopped() {return !instance()->m_started.loadRelaxed(); } void startAll(); void stopAll(); void addEventDispatcher(QAndroidEventDispatcher *dispatcher); diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index db40c30d7d..5614d3b04f 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -64,29 +64,33 @@ QT_BEGIN_NAMESPACE -template <typename T> -class ScopedValueChangeBack +namespace { + +class BatchEditLock { public: - ScopedValueChangeBack(T &variable, T newValue) - : m_oldValue(variable), - m_variable(variable) - { - m_variable = newValue; - } - inline void setOldValue() + + explicit BatchEditLock(QAndroidInputContext *context) + : m_context(context) { - m_variable = m_oldValue; + m_context->beginBatchEdit(); } - ~ScopedValueChangeBack() + + ~BatchEditLock() { - setOldValue(); + m_context->endBatchEdit(); } + + BatchEditLock(const BatchEditLock &) = delete; + BatchEditLock &operator=(const BatchEditLock &) = delete; + private: - T m_oldValue; - T &m_variable; + + QAndroidInputContext *m_context; }; +} // namespace anonymous + static QAndroidInputContext *m_androidInputContext = 0; static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection"; static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText"; @@ -423,8 +427,12 @@ static QRect inputItemRectangle() } QAndroidInputContext::QAndroidInputContext() - : QPlatformInputContext(), m_composingTextStart(-1), m_blockUpdateSelection(false), - m_handleMode(Hidden), m_batchEditNestingLevel(0), m_focusObject(0) + : QPlatformInputContext() + , m_composingTextStart(-1) + , m_composingCursor(-1) + , m_handleMode(Hidden) + , m_batchEditNestingLevel(0) + , m_focusObject(0) { jclass clazz = QJNIEnvironmentPrivate::findClass(QtNativeInputConnectionClassName); if (Q_UNLIKELY(!clazz)) { @@ -550,6 +558,7 @@ static inline int getBlockPosition(const QSharedPointer<QInputMethodQueryEvent> void QAndroidInputContext::reset() { + focusObjectStopComposing(); clear(); m_batchEditNestingLevel = 0; m_handleMode = Hidden; @@ -565,13 +574,13 @@ void QAndroidInputContext::reset() void QAndroidInputContext::commit() { - finishComposingText(); + focusObjectStopComposing(); } void QAndroidInputContext::updateCursorPosition() { QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - if (!query.isNull() && !m_blockUpdateSelection && !m_batchEditNestingLevel) { + if (!query.isNull() && m_batchEditNestingLevel == 0) { const int cursorPos = getAbsoluteCursorPosition(query); const int composeLength = m_composingText.length(); @@ -579,24 +588,29 @@ void QAndroidInputContext::updateCursorPosition() if (m_composingText.isEmpty() != (m_composingTextStart == -1)) qWarning() << "Input method out of sync" << m_composingText << m_composingTextStart; - int realCursorPosition = cursorPos; - int realAnchorPosition = cursorPos; + int realSelectionStart = cursorPos; + int realSelectionEnd = cursorPos; int cpos = query->value(Qt::ImCursorPosition).toInt(); int anchor = query->value(Qt::ImAnchorPosition).toInt(); if (cpos != anchor) { if (!m_composingText.isEmpty()) { qWarning("Selecting text while preediting may give unpredictable results."); - finishComposingText(); + focusObjectStopComposing(); } int blockPos = getBlockPosition(query); - realCursorPosition = blockPos + cpos; - realAnchorPosition = blockPos + anchor; + realSelectionStart = blockPos + cpos; + realSelectionEnd = blockPos + anchor; } // Qt's idea of the cursor position is the start of the preedit area, so we maintain our own preedit cursor pos - if (!m_composingText.isEmpty()) - realCursorPosition = realAnchorPosition = m_composingCursor; - QtAndroidInput::updateSelection(realCursorPosition, realAnchorPosition, + if (focusObjectIsComposing()) + realSelectionStart = realSelectionEnd = m_composingCursor; + + // Some keyboards misbahave when selStart > selEnd + if (realSelectionStart > realSelectionEnd) + std::swap(realSelectionStart, realSelectionEnd); + + QtAndroidInput::updateSelection(realSelectionStart, realSelectionEnd, m_composingTextStart, m_composingTextStart + composeLength); // pre-edit text } } @@ -666,13 +680,11 @@ void QAndroidInputContext::updateSelectionHandles() */ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) { - if (m_batchEditNestingLevel.load() || m_blockUpdateSelection) { + if (m_batchEditNestingLevel != 0) { qWarning() << "QAndroidInputContext::handleLocationChanged returned"; return; } - finishComposingText(); - auto im = qGuiApp->inputMethod(); auto leftRect = im->cursorRectangle(); // The handle is down of the cursor, but we want the position in the middle. @@ -682,63 +694,96 @@ void QAndroidInputContext::handleLocationChanged(int handleId, int x, int y) : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); QPointF point(x / pixelDensity, y / pixelDensity); point.setY(point.y() - leftRect.width() / 2); - if (handleId == 1) { - setSelectionOnFocusObject(point, point); - return; - } - QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImCurrentSelection); + QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition + | Qt::ImAbsolutePosition | Qt::ImCurrentSelection); QCoreApplication::sendEvent(m_focusObject, &query); int cpos = query.value(Qt::ImCursorPosition).toInt(); int anchor = query.value(Qt::ImAnchorPosition).toInt(); - bool rtl = query.value(Qt::ImCurrentSelection).toString().isRightToLeft(); auto rightRect = im->anchorRectangle(); if (cpos > anchor) std::swap(leftRect, rightRect); - auto checkLeftHandle = [&rightRect](QPointF &handlePos) { - if (handlePos.y() > rightRect.center().y()) - handlePos.setY(rightRect.center().y()); // adjust Y handle pos - if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && handlePos.x() >= rightRect.x()) - return false; // same line and wrong X pos ? - return true; - }; - - auto checkRtlRightHandle = [&rightRect](QPointF &handlePos) { - if (handlePos.y() > rightRect.center().y()) - handlePos.setY(rightRect.center().y()); // adjust Y handle pos - if (handlePos.y() >= rightRect.y() && handlePos.y() <= rightRect.bottom() && rightRect.x() >= handlePos.x()) - return false; // same line and wrong X pos ? - return true; - }; - - auto checkRightHandle = [&leftRect](QPointF &handlePos) { - if (handlePos.y() < leftRect.center().y()) - handlePos.setY(leftRect.center().y()); // adjust Y handle pos - if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && leftRect.x() >= handlePos.x()) - return false; // same line and wrong X pos ? - return true; - }; - - auto checkRtlLeftHandle = [&leftRect](QPointF &handlePos) { - if (handlePos.y() < leftRect.center().y()) - handlePos.setY(leftRect.center().y()); // adjust Y handle pos - if (handlePos.y() >= leftRect.y() && handlePos.y() <= leftRect.bottom() && handlePos.x() >= leftRect.x()) - return false; // same line and wrong X pos ? - return true; - }; - - if (handleId == 2) { - QPointF rightPoint(rightRect.center()); - if ((!rtl && !checkLeftHandle(point)) || (rtl && !checkRtlRightHandle(point))) - return; - setSelectionOnFocusObject(point, rightPoint); + // Do not allow dragging left handle below right handle, or right handle above left handle + if (handleId == 2 && point.y() > rightRect.center().y()) { + point.setY(rightRect.center().y()); + } else if (handleId == 3 && point.y() < leftRect.center().y()) { + point.setY(leftRect.center().y()); + } + + const QPointF pointLocal = im->inputItemTransform().inverted().map(point); + bool ok; + const int handlePos = + QInputMethod::queryFocusObject(Qt::ImCursorPosition, pointLocal).toInt(&ok); + if (!ok) + return; + + int newCpos = cpos; + int newAnchor = anchor; + if (newAnchor > newCpos) + std::swap(newAnchor, newCpos); + + if (handleId == 1) { + newCpos = handlePos; + newAnchor = handlePos; + } else if (handleId == 2) { + newAnchor = handlePos; } else if (handleId == 3) { - QPointF leftPoint(leftRect.center()); - if ((!rtl && !checkRightHandle(point)) || (rtl && !checkRtlLeftHandle(point))) + newCpos = handlePos; + } + + /* + Do not allow clearing selection by dragging selection handles and do not allow swapping + selection handles for consistency with Android's native text editing controls. Ensure that at + least one symbol remains selected. + */ + if ((handleId == 2 || handleId == 3) && newCpos <= newAnchor) { + QTextBoundaryFinder finder(QTextBoundaryFinder::Grapheme, + query.value(Qt::ImCurrentSelection).toString()); + + const int oldSelectionStartPos = qMin(cpos, anchor); + + if (handleId == 2) { + finder.toEnd(); + finder.toPreviousBoundary(); + newAnchor = finder.position() + oldSelectionStartPos; + } else { + finder.toStart(); + finder.toNextBoundary(); + newCpos = finder.position() + oldSelectionStartPos; + } + } + + // Check if handle has been dragged far enough + if (!focusObjectIsComposing() && newCpos == cpos && newAnchor == anchor) + return; + + /* + If the editor is currently in composing state, we have to compare newCpos with + m_composingCursor instead of cpos. And since there is nothing to compare with newAnchor, we + perform the check only when user drags the cursor handle. + */ + if (focusObjectIsComposing() && handleId == 1) { + int absoluteCpos = query.value(Qt::ImAbsolutePosition).toInt(&ok); + if (!ok) + absoluteCpos = cpos; + const int blockPos = absoluteCpos - cpos; + + if (blockPos + newCpos == m_composingCursor) return; - setSelectionOnFocusObject(leftPoint, point); } + + BatchEditLock batchEditLock(this); + + focusObjectStopComposing(); + + QList<QInputMethodEvent::Attribute> attributes; + attributes.append({ QInputMethodEvent::Selection, newAnchor, newCpos - newAnchor }); + if (newCpos != newAnchor) + attributes.append({ QInputMethodEvent::Cursor, 0, 0 }); + + QInputMethodEvent event(QString(), attributes); + QGuiApplication::sendEvent(m_focusObject, &event); } void QAndroidInputContext::touchDown(int x, int y) @@ -748,7 +793,25 @@ void QAndroidInputContext::touchDown(int x, int y) m_handleMode = ShowCursor; // The VK will appear in a moment, stop the timer m_hideCursorHandleTimer.stop(); - finishComposingText(); + + if (focusObjectIsComposing()) { + const double pixelDensity = + QGuiApplication::focusWindow() + ? QHighDpiScaling::factor(QGuiApplication::focusWindow()) + : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); + + const QPointF touchPointLocal = + QGuiApplication::inputMethod()->inputItemTransform().inverted().map( + QPointF(x / pixelDensity, y / pixelDensity)); + + const int curBlockPos = getBlockPosition( + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition)); + const int touchPosition = curBlockPos + + QInputMethod::queryFocusObject(Qt::ImCursorPosition, touchPointLocal).toInt(); + if (touchPosition != m_composingCursor) + focusObjectStopComposing(); + } + updateSelectionHandles(); } } @@ -760,13 +823,19 @@ void QAndroidInputContext::longPress(int x, int y) return; if (m_focusObject && inputItemRectangle().contains(x, y)) { - finishComposingText(); + BatchEditLock batchEditLock(this); + + focusObjectStopComposing(); // Release left button, otherwise the following events will cancel the menu popup QtAndroidInput::releaseMouse(x, y); - handleLocationChanged(1, x, y); - ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true); + const double pixelDensity = + QGuiApplication::focusWindow() + ? QHighDpiScaling::factor(QGuiApplication::focusWindow()) + : QHighDpiScaling::factor(QtAndroid::androidPlatformIntegration()->screen()); + const QPointF touchPoint(x / pixelDensity, y / pixelDensity); + setSelectionOnFocusObject(touchPoint, touchPoint); QInputMethodQueryEvent query(Qt::ImCursorPosition | Qt::ImAnchorPosition | Qt::ImTextBeforeCursor | Qt::ImTextAfterCursor); QCoreApplication::sendEvent(m_focusObject, &query); @@ -905,6 +974,7 @@ void QAndroidInputContext::clear() { m_composingText.clear(); m_composingTextStart = -1; + m_composingCursor = -1; m_extractedText.clear(); } @@ -912,9 +982,8 @@ void QAndroidInputContext::clear() void QAndroidInputContext::setFocusObject(QObject *object) { if (object != m_focusObject) { + focusObjectStopComposing(); m_focusObject = object; - if (!m_composingText.isEmpty()) - finishComposingText(); reset(); } QPlatformInputContext::setFocusObject(object); @@ -929,78 +998,135 @@ jboolean QAndroidInputContext::beginBatchEdit() jboolean QAndroidInputContext::endBatchEdit() { - if (--m_batchEditNestingLevel == 0 && !m_blockUpdateSelection) //ending batch edit mode + if (--m_batchEditNestingLevel == 0) { //ending batch edit mode + focusObjectStartComposing(); updateCursorPosition(); + } return JNI_TRUE; } /* - Android docs say: If composing, replace compose text with \a text. - Otherwise insert \a text at current cursor position. - - The cursor should then be 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. updateSelection() needs to be called. + Android docs say: This behaves like calling setComposingText(text, newCursorPosition) then + finishComposingText(). */ jboolean QAndroidInputContext::commitText(const QString &text, jint newCursorPosition) { - ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true); - QInputMethodEvent event; - event.setCommitString(text); - sendInputMethodEvent(&event); - clear(); - - // Qt has now put the cursor at the end of the text, corresponding to newCursorPosition == 1 - if (newCursorPosition != 1) { - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - if (!query.isNull()) { - QList<QInputMethodEvent::Attribute> attributes; - const int localPos = query->value(Qt::ImCursorPosition).toInt(); - const int newLocalPos = newCursorPosition > 0 - ? localPos + newCursorPosition - 1 - : localPos - text.length() + newCursorPosition; - //move the cursor - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, - newLocalPos, 0)); - } - } - svcb.setOldValue(); - updateCursorPosition(); - return JNI_TRUE; + BatchEditLock batchEditLock(this); + return setComposingText(text, newCursorPosition) && finishComposingText(); } jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength) { + BatchEditLock batchEditLock(this); + + focusObjectStopComposing(); + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (query.isNull()) return JNI_TRUE; - m_composingText.clear(); - m_composingTextStart = -1; - if (leftLength < 0) { rightLength += -leftLength; leftLength = 0; } + const int initialBlockPos = getBlockPosition(query); + const int initialCursorPos = getAbsoluteCursorPosition(query); + const int initialAnchorPos = initialBlockPos + query->value(Qt::ImAnchorPosition).toInt(); + + /* + According to documentation, we should delete leftLength characters before current selection + and rightLength characters after current selection (without affecting selection). But that is + absolutely not what Android's native EditText does. It deletes leftLength characters before + min(selection start, composing region start) and rightLength characters after max(selection + end, composing region end). There are no known keyboards that depend on this behavior, but + it is better to be consistent with EditText behavior, because there definetly should be no + keyboards that depend on documented behavior. + */ + const int leftEnd = + m_composingText.isEmpty() + ? qMin(initialCursorPos, initialAnchorPos) + : qMin(qMin(initialCursorPos, initialAnchorPos), m_composingTextStart); + + const int rightBegin = + m_composingText.isEmpty() + ? qMax(initialCursorPos, initialAnchorPos) + : qMax(qMax(initialCursorPos, initialAnchorPos), + m_composingTextStart + m_composingText.length()); + + int textBeforeCursorLen; + int textAfterCursorLen; + QVariant textBeforeCursor = query->value(Qt::ImTextBeforeCursor); QVariant textAfterCursor = query->value(Qt::ImTextAfterCursor); if (textBeforeCursor.isValid() && textAfterCursor.isValid()) { - leftLength = qMin(leftLength, textBeforeCursor.toString().length()); - rightLength = qMin(rightLength, textAfterCursor.toString().length()); + textBeforeCursorLen = textBeforeCursor.toString().length(); + textAfterCursorLen = textAfterCursor.toString().length(); } else { - int cursorPos = query->value(Qt::ImCursorPosition).toInt(); - leftLength = qMin(leftLength, cursorPos); - rightLength = qMin(rightLength, query->value(Qt::ImSurroundingText).toString().length() - cursorPos); + textBeforeCursorLen = initialCursorPos - initialBlockPos; + textAfterCursorLen = + query->value(Qt::ImSurroundingText).toString().length() - textBeforeCursorLen; } + leftLength = qMin(qMax(0, textBeforeCursorLen - (initialCursorPos - leftEnd)), leftLength); + rightLength = qMin(qMax(0, textAfterCursorLen - (rightBegin - initialCursorPos)), rightLength); + if (leftLength == 0 && rightLength == 0) return JNI_TRUE; - QInputMethodEvent event; - event.setCommitString(QString(), -leftLength, leftLength+rightLength); - sendInputMethodEvent(&event); - clear(); + if (leftEnd == rightBegin) { + // We have no selection and no composing region; we can do everything using one event + QInputMethodEvent event; + event.setCommitString({}, -leftLength, leftLength + rightLength); + QGuiApplication::sendEvent(m_focusObject, &event); + } else { + if (initialCursorPos != initialAnchorPos) { + QInputMethodEvent event({}, { + { QInputMethodEvent::Selection, initialCursorPos - initialBlockPos, 0 } + }); + + QGuiApplication::sendEvent(m_focusObject, &event); + } + + int currentCursorPos = initialCursorPos; + + if (rightLength > 0) { + QInputMethodEvent event; + event.setCommitString({}, rightBegin - currentCursorPos, rightLength); + QGuiApplication::sendEvent(m_focusObject, &event); + + currentCursorPos = rightBegin; + } + + if (leftLength > 0) { + const int leftBegin = leftEnd - leftLength; + + QInputMethodEvent event; + event.setCommitString({}, leftBegin - currentCursorPos, leftLength); + QGuiApplication::sendEvent(m_focusObject, &event); + + currentCursorPos = leftBegin; + + if (!m_composingText.isEmpty()) + m_composingTextStart -= leftLength; + } + + // Restore cursor position or selection + if (currentCursorPos != initialCursorPos - leftLength + || initialCursorPos != initialAnchorPos) { + // If we have deleted a newline character, we are now in a new block + const int currentBlockPos = getBlockPosition( + focusObjectInputMethodQuery(Qt::ImAbsolutePosition | Qt::ImCursorPosition)); + + QInputMethodEvent event({}, { + { QInputMethodEvent::Selection, initialCursorPos - leftLength - currentBlockPos, + initialAnchorPos - initialCursorPos }, + { QInputMethodEvent::Cursor, 0, 0 } + }); + + QGuiApplication::sendEvent(m_focusObject, &event); + } + } return JNI_TRUE; } @@ -1008,16 +1134,70 @@ jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint right // Android docs say the cursor must not move jboolean QAndroidInputContext::finishComposingText() { - if (m_composingText.isEmpty()) - return JNI_TRUE; // not composing + BatchEditLock batchEditLock(this); + + if (!focusObjectStopComposing()) + return JNI_FALSE; + + clear(); + return JNI_TRUE; +} + +bool QAndroidInputContext::focusObjectIsComposing() const +{ + return m_composingCursor != -1; +} + +void QAndroidInputContext::focusObjectStartComposing() +{ + if (focusObjectIsComposing() || m_composingText.isEmpty()) + return; + + // Composing strings containing newline characters are rare and may cause problems + if (m_composingText.contains(QLatin1Char('\n'))) + return; + + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); + if (!query) + return; + + if (query->value(Qt::ImCursorPosition).toInt() != query->value(Qt::ImAnchorPosition).toInt()) + return; + + const int absoluteCursorPos = getAbsoluteCursorPosition(query); + if (absoluteCursorPos < m_composingTextStart + || absoluteCursorPos > m_composingTextStart + m_composingText.length()) + return; + + m_composingCursor = absoluteCursorPos; + + QTextCharFormat underlined; + underlined.setFontUnderline(true); + + QInputMethodEvent event(m_composingText, { + { QInputMethodEvent::Cursor, absoluteCursorPos - m_composingTextStart, 1 }, + { QInputMethodEvent::TextFormat, 0, m_composingText.length(), underlined } + }); + + event.setCommitString({}, m_composingTextStart - absoluteCursorPos, m_composingText.length()); + + QGuiApplication::sendEvent(m_focusObject, &event); +} + +bool QAndroidInputContext::focusObjectStopComposing() +{ + if (!focusObjectIsComposing()) + return true; // not composing QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (query.isNull()) - return JNI_FALSE; + return false; const int blockPos = getBlockPosition(query); const int localCursorPos = m_composingCursor - blockPos; + m_composingCursor = -1; + // Moving Qt's cursor to where the preedit cursor used to be QList<QInputMethodEvent::Attribute> attributes; attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, 0)); @@ -1025,9 +1205,8 @@ jboolean QAndroidInputContext::finishComposingText() QInputMethodEvent event(QString(), attributes); event.setCommitString(m_composingText); sendInputMethodEvent(&event); - clear(); - return JNI_TRUE; + return true; } jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/) @@ -1040,13 +1219,18 @@ jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/) const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt(); const int localPos = query->value(Qt::ImCursorPosition).toInt(); - bool atWordBoundary = (localPos == 0); + bool atWordBoundary = + localPos == 0 + && (!focusObjectIsComposing() || m_composingCursor == m_composingTextStart); + if (!atWordBoundary) { QString surroundingText = query->value(Qt::ImSurroundingText).toString(); surroundingText.truncate(localPos); + if (focusObjectIsComposing()) + surroundingText += m_composingText.leftRef(m_composingCursor - m_composingTextStart); // Add a character to see if it is at the end of the sentence or not QTextBoundaryFinder finder(QTextBoundaryFinder::Sentence, surroundingText + QLatin1Char('A')); - finder.setPosition(localPos); + finder.setPosition(surroundingText.length()); if (finder.isAtBoundary()) atWordBoundary = finder.isAtBoundary(); } @@ -1067,52 +1251,51 @@ const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedTex // updateExtractedText(View, int, ExtractedText) whenever you call // updateSelection(View, int, int, int, int)." QTBUG-37980 - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); + QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery( + Qt::ImCursorPosition | Qt::ImAbsolutePosition | Qt::ImAnchorPosition); if (query.isNull()) return m_extractedText; - int localPos = query->value(Qt::ImCursorPosition).toInt(); //position before pre-edit text relative to the current block - 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.leftRef(localComposePos) + m_composingText + blockText.midRef(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 (blockPos > 0) { - QString prevBlockEnding = query->value(Qt::ImTextBeforeCursor).toString(); - prevBlockEnding.chop(localPos); - if (prevBlockEnding.endsWith(QLatin1Char('\n'))) { - localOffset = -qMin(20, prevBlockEnding.length()); - blockText = prevBlockEnding.right(-localOffset) + blockText; - } - } + const int cursorPos = getAbsoluteCursorPosition(query); + const int blockPos = getBlockPosition(query); // It is documented that we should try to return hintMaxChars - // characters, but that's not what the standard Android controls do, and + // characters, but standard Android controls always return all text, 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; + QVariant textBeforeCursor = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, INT_MAX); + QVariant textAfterCursor = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, INT_MAX); + if (textBeforeCursor.isValid() && textAfterCursor.isValid()) { + if (focusObjectIsComposing()) { + m_extractedText.text = + textBeforeCursor.toString() + m_composingText + textAfterCursor.toString(); + } else { + m_extractedText.text = textBeforeCursor.toString() + textAfterCursor.toString(); + } + + m_extractedText.startOffset = qMax(0, cursorPos - textBeforeCursor.toString().length()); + } else { + m_extractedText.text = focusObjectInputMethodQuery(Qt::ImSurroundingText) + ->value(Qt::ImSurroundingText).toString(); + + if (focusObjectIsComposing()) + m_extractedText.text.insert(cursorPos - blockPos, m_composingText); + + m_extractedText.startOffset = blockPos; + } - 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 if (composeLength > 0) { + if (focusObjectIsComposing()) { 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; + m_extractedText.selectionEnd = m_extractedText.selectionStart; + } else { + m_extractedText.selectionStart = cursorPos - m_extractedText.startOffset; + m_extractedText.selectionEnd = + blockPos + query->value(Qt::ImAnchorPosition).toInt() - m_extractedText.startOffset; + + // Some keyboards misbehave when selectionStart > selectionEnd + if (m_extractedText.selectionStart > m_extractedText.selectionEnd) + std::swap(m_extractedText.selectionStart, m_extractedText.selectionEnd); } return m_extractedText; @@ -1147,10 +1330,20 @@ QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/) } } - // Controls do not report preedit text, so we have to add it - if (!m_composingText.isEmpty()) { + if (focusObjectIsComposing()) { + // Controls do not report preedit text, so we have to add it const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart; text = m_composingText.midRef(cursorPosInsidePreedit) + text; + } else { + // We must not return selected text if there is any + QSharedPointer<QInputMethodQueryEvent> query = + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition); + if (query) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); + const int anchorPos = query->value(Qt::ImAnchorPosition).toInt(); + if (anchorPos > cursorPos) + text.remove(0, anchorPos - cursorPos); + } } text.truncate(length); @@ -1177,10 +1370,20 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) } } - // Controls do not report preedit text, so we have to add it - if (!m_composingText.isEmpty()) { + if (focusObjectIsComposing()) { + // Controls do not report preedit text, so we have to add it const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart; text += m_composingText.leftRef(cursorPosInsidePreedit); + } else { + // We must not return selected text if there is any + QSharedPointer<QInputMethodQueryEvent> query = + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAnchorPosition); + if (query) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); + const int anchorPos = query->value(Qt::ImAnchorPosition).toInt(); + if (anchorPos < cursorPos) + text.chop(cursorPos - anchorPos); + } } if (text.length() > length) @@ -1189,11 +1392,13 @@ QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) } /* - 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. + Android docs say that this function should: + - remove the current composing text, if there is any + - otherwise remove currently selected text, if there is any + - insert new text in place of old composing text or, if there was none, at current cursor position + - mark the inserted text as composing + - move cursor as specified by newCursorPosition: if > 0, it is relative to the end of inserted + text - 1; if <= 0, it is relative to the start of inserted text */ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition) @@ -1202,47 +1407,110 @@ jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCur if (query.isNull()) return JNI_FALSE; - const int cursorPos = getAbsoluteCursorPosition(query); - if (newCursorPosition > 0) - newCursorPosition += text.length() - 1; + BatchEditLock batchEditLock(this); + + const int absoluteCursorPos = getAbsoluteCursorPosition(query); + int absoluteAnchorPos = getBlockPosition(query) + query->value(Qt::ImAnchorPosition).toInt(); + // If we have composing region and selection (and therefore focusObjectIsComposing() == false), + // we must clear selection so that we won't delete it when we will be replacing composing text + if (!m_composingText.isEmpty() && absoluteCursorPos != absoluteAnchorPos) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); + QInputMethodEvent event({}, { { QInputMethodEvent::Selection, cursorPos, 0 } }); + QGuiApplication::sendEvent(m_focusObject, &event); + + absoluteAnchorPos = absoluteCursorPos; + } + + // If we had no composing region, pretend that we had a zero-length composing region at current + // cursor position to simplify code. Also account for that we must delete selected text if there + // (still) is any. + const int effectiveAbsoluteCursorPos = qMin(absoluteCursorPos, absoluteAnchorPos); + if (m_composingTextStart == -1) + m_composingTextStart = effectiveAbsoluteCursorPos; + + const int oldComposingTextLen = m_composingText.length(); m_composingText = text; - m_composingTextStart = text.isEmpty() ? -1 : cursorPos; - m_composingCursor = cursorPos + newCursorPosition; - QList<QInputMethodEvent::Attribute> attributes; - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, - newCursorPosition, - 1)); - // Show compose text underlined - QTextCharFormat underlined; - underlined.setFontUnderline(true); - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, text.length(), - QVariant(underlined))); - QInputMethodEvent event(m_composingText, attributes); - sendInputMethodEvent(&event); + const int newAbsoluteCursorPos = + newCursorPosition <= 0 + ? m_composingTextStart + newCursorPosition + : m_composingTextStart + m_composingText.length() + newCursorPosition - 1; - QMetaObject::invokeMethod(this, "keyDown"); + const bool focusObjectWasComposing = focusObjectIsComposing(); - updateCursorPosition(); + // Same checks as in focusObjectStartComposing() + if (!m_composingText.isEmpty() && !m_composingText.contains(QLatin1Char('\n')) + && newAbsoluteCursorPos >= m_composingTextStart + && newAbsoluteCursorPos <= m_composingTextStart + m_composingText.length()) + m_composingCursor = newAbsoluteCursorPos; + else + m_composingCursor = -1; + + QInputMethodEvent event; + if (focusObjectIsComposing()) { + QTextCharFormat underlined; + underlined.setFontUnderline(true); + + event = QInputMethodEvent(m_composingText, { + { QInputMethodEvent::TextFormat, 0, m_composingText.length(), underlined }, + { QInputMethodEvent::Cursor, m_composingCursor - m_composingTextStart, 1 } + }); + + if (oldComposingTextLen > 0 && !focusObjectWasComposing) { + event.setCommitString({}, m_composingTextStart - effectiveAbsoluteCursorPos, + oldComposingTextLen); + } + } else { + event = QInputMethodEvent({}, {}); + + if (focusObjectWasComposing) { + event.setCommitString(m_composingText); + } else { + event.setCommitString(m_composingText, + m_composingTextStart - effectiveAbsoluteCursorPos, + oldComposingTextLen); + } + } + + if (m_composingText.isEmpty()) + clear(); + + QGuiApplication::sendEvent(m_focusObject, &event); + + if (!focusObjectIsComposing() && newCursorPosition != 1) { + // Move cursor using a separate event because if we have inserted or deleted a newline + // character, then we are now inside an another block + + const int newBlockPos = getBlockPosition( + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImAbsolutePosition)); + + event = QInputMethodEvent({}, { + { QInputMethodEvent::Selection, newAbsoluteCursorPos - newBlockPos, 0 } + }); + + QGuiApplication::sendEvent(m_focusObject, &event); + } + + keyDown(); return JNI_TRUE; } // Android docs say: // * start may be after end, same meaning as if swapped -// * this function should not trigger updateSelection +// * this function should not trigger updateSelection, but Android's native EditText does trigger it // * if start == end then we should stop composing jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) { + BatchEditLock batchEditLock(this); + // 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(); + finishComposingText(); QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); if (query.isNull()) @@ -1253,54 +1521,42 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) if (start > end) qSwap(start, end); - /* - start and end are cursor positions, not character positions, - i.e. selecting the first character is done by start == 0 and end == 1, - and start == end means no character selected - - Therefore, the length of the region is end - start - */ - - int length = end - start; - int localPos = query->value(Qt::ImCursorPosition).toInt(); - int blockPosition = getBlockPosition(query); - int localStart = start - blockPosition; // Qt uses position inside block - int currentCursor = wasComposing ? m_composingCursor : blockPosition + localPos; - - ScopedValueChangeBack<bool> svcb(m_blockUpdateSelection, true); - QString text = query->value(Qt::ImSurroundingText).toString(); + int textOffset = getBlockPosition(query); - m_composingText = text.mid(localStart, length); - m_composingTextStart = start; - m_composingCursor = currentCursor; - - //in the Qt text controls, the preedit is defined relative to the cursor position - int relativeStart = localStart - localPos; + if (start < textOffset || end > textOffset + text.length()) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); - QList<QInputMethodEvent::Attribute> attributes; + if (end - textOffset > text.length()) { + const QString after = query->value(Qt::ImTextAfterCursor).toString(); + const int additionalSuffixLen = after.length() - (text.length() - cursorPos); - // Show compose text underlined - QTextCharFormat underlined; - underlined.setFontUnderline(true); - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, length, - QVariant(underlined))); + if (additionalSuffixLen > 0) + text += after.rightRef(additionalSuffixLen); + } - // Keep the cursor position unchanged (don't move to end of preedit) - attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, currentCursor - start, 1)); + if (start < textOffset) { + QString before = query->value(Qt::ImTextBeforeCursor).toString(); + before.chop(cursorPos); - QInputMethodEvent event(m_composingText, attributes); - event.setCommitString(QString(), relativeStart, length); - sendInputMethodEvent(&event); + if (!before.isEmpty()) { + text = before + text; + textOffset -= before.length(); + } + } + if (start < textOffset || end - textOffset > text.length()) { #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); - } + qWarning("setComposingRegion: failed to retrieve text from composing region"); #endif + return JNI_TRUE; + } + } + + m_composingText = text.mid(start - textOffset, end - start); + m_composingTextStart = start; + return JNI_TRUE; } @@ -1310,15 +1566,18 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end) if (query.isNull()) return JNI_FALSE; + BatchEditLock batchEditLock(this); + int blockPosition = getBlockPosition(query); int localCursorPos = start - blockPosition; - QList<QInputMethodEvent::Attribute> attributes; - if (!m_composingText.isEmpty() && start == end) { + if (focusObjectIsComposing() && start == end && start >= m_composingTextStart + && start <= m_composingTextStart + m_composingText.length()) { // not actually changing the selection; just moving the // preedit cursor int localOldPos = query->value(Qt::ImCursorPosition).toInt(); int pos = localCursorPos - localOldPos; + QList<QInputMethodEvent::Attribute> attributes; attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, pos, 1)); //but we have to tell Qt about the compose text all over again @@ -1330,21 +1589,26 @@ jboolean QAndroidInputContext::setSelection(jint start, jint end) QVariant(underlined))); m_composingCursor = start; + QInputMethodEvent event(m_composingText, attributes); + QGuiApplication::sendEvent(m_focusObject, &event); } else { // actually changing the selection + focusObjectStopComposing(); + QList<QInputMethodEvent::Attribute> attributes; attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection, localCursorPos, end - start)); + QInputMethodEvent event({}, attributes); + QGuiApplication::sendEvent(m_focusObject, &event); } - QInputMethodEvent event(m_composingText, attributes); - sendInputMethodEvent(&event); - updateCursorPosition(); return JNI_TRUE; } jboolean QAndroidInputContext::selectAll() { - finishComposingText(); + BatchEditLock batchEditLock(this); + + focusObjectStopComposing(); m_handleMode = ShowCursor; sendShortcut(QKeySequence::SelectAll); return JNI_TRUE; @@ -1352,7 +1616,12 @@ jboolean QAndroidInputContext::selectAll() jboolean QAndroidInputContext::cut() { + BatchEditLock batchEditLock(this); + + // This is probably not what native EditText would do, but normally if there is selection, then + // there will be no composing region finishComposingText(); + m_handleMode = ShowCursor; sendShortcut(QKeySequence::Cut); return JNI_TRUE; @@ -1360,7 +1629,9 @@ jboolean QAndroidInputContext::cut() jboolean QAndroidInputContext::copy() { - finishComposingText(); + BatchEditLock batchEditLock(this); + + focusObjectStopComposing(); m_handleMode = ShowCursor; sendShortcut(QKeySequence::Copy); return JNI_TRUE; @@ -1374,7 +1645,11 @@ jboolean QAndroidInputContext::copyURL() jboolean QAndroidInputContext::paste() { + BatchEditLock batchEditLock(this); + + // TODO: This is not what native EditText does finishComposingText(); + m_handleMode = ShowCursor; sendShortcut(QKeySequence::Paste); return JNI_TRUE; @@ -1386,8 +1661,12 @@ void QAndroidInputContext::sendShortcut(const QKeySequence &sequence) const int keys = sequence[i]; Qt::Key key = Qt::Key(keys & ~Qt::KeyboardModifierMask); Qt::KeyboardModifiers mod = Qt::KeyboardModifiers(keys & Qt::KeyboardModifierMask); - QGuiApplication::postEvent(m_focusObject, new QKeyEvent(QEvent::KeyPress, key, mod)); - QGuiApplication::postEvent(m_focusObject, new QKeyEvent(QEvent::KeyRelease, key, mod)); + + QKeyEvent pressEvent(QEvent::KeyPress, key, mod); + QKeyEvent releaseEvent(QEvent::KeyRelease, key, mod); + + QGuiApplication::sendEvent(m_focusObject, &pressEvent); + QGuiApplication::sendEvent(m_focusObject, &releaseEvent); } } diff --git a/src/plugins/platforms/android/qandroidinputcontext.h b/src/plugins/platforms/android/qandroidinputcontext.h index bd3edb30f0..e9bfb98e66 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.h +++ b/src/plugins/platforms/android/qandroidinputcontext.h @@ -151,6 +151,9 @@ private slots: private: void sendInputMethodEvent(QInputMethodEvent *event); QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll); + bool focusObjectIsComposing() const; + void focusObjectStartComposing(); + bool focusObjectStopComposing(); private: ExtractedText m_extractedText; @@ -158,9 +161,8 @@ private: int m_composingTextStart; int m_composingCursor; QMetaObject::Connection m_updateCursorPosConnection; - bool m_blockUpdateSelection; HandleModes m_handleMode; - QAtomicInt m_batchEditNestingLevel; + int m_batchEditNestingLevel; QObject *m_focusObject; QTimer m_hideCursorHandleTimer; }; diff --git a/src/plugins/platforms/android/qandroidplatformtheme.cpp b/src/plugins/platforms/android/qandroidplatformtheme.cpp index a78a62337f..7fc68c3d7c 100644 --- a/src/plugins/platforms/android/qandroidplatformtheme.cpp +++ b/src/plugins/platforms/android/qandroidplatformtheme.cpp @@ -489,6 +489,8 @@ QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const Q_FALLTHROUGH(); } + case DialogButtonBoxLayout: + return QVariant(QPlatformDialogHelper::AndroidLayout); default: return QPlatformTheme::themeHint(hint); } diff --git a/src/plugins/platforms/android/qandroidplatformwindow.cpp b/src/plugins/platforms/android/qandroidplatformwindow.cpp index c095f51fa3..4f691ce112 100644 --- a/src/plugins/platforms/android/qandroidplatformwindow.cpp +++ b/src/plugins/platforms/android/qandroidplatformwindow.cpp @@ -49,13 +49,14 @@ QT_BEGIN_NAMESPACE +static QBasicAtomicInt winIdGenerator = Q_BASIC_ATOMIC_INITIALIZER(0); + QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) : QPlatformWindow(window) { m_windowFlags = Qt::Widget; m_windowState = Qt::WindowNoState; - static QAtomicInt winIdGenerator(1); - m_windowId = winIdGenerator.fetchAndAddRelaxed(1); + m_windowId = winIdGenerator.fetchAndAddRelaxed(1) + 1; setWindowState(window->windowStates()); } diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.h b/src/plugins/platforms/cocoa/qcocoabackingstore.h index acddc3ecc8..2398e6351e 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.h +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.h @@ -55,6 +55,7 @@ public: QNSWindowBackingStore(QWindow *window); ~QNSWindowBackingStore(); + void resize(const QSize &size, const QRegion &staticContents) override; void flush(QWindow *, const QRegion &, const QPoint &) override; private: diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm index c381f87844..01b4894324 100644 --- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm +++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm @@ -71,6 +71,24 @@ QImage::Format QNSWindowBackingStore::format() const return QRasterBackingStore::format(); } +void QNSWindowBackingStore::resize(const QSize &size, const QRegion &staticContents) +{ + qCDebug(lcQpaBackingStore) << "Resize requested to" << size; + QRasterBackingStore::resize(size, staticContents); + + // The window shadow rendered by AppKit is based on the shape/content of the + // NSWindow surface. Technically any flush of the backingstore can result in + // a potentially new shape of the window, and would need a shadow invalidation, + // but this is likely too expensive to do at every flush for the few cases where + // clients change the shape dynamically. One case where we do know that the shadow + // likely needs invalidation, if the window has partially transparent content, + // is after a resize, where AppKit's default shadow may be based on the previous + // window content. + QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(window()->handle()); + if (cocoaWindow->isContentView() && !cocoaWindow->isOpaque()) + cocoaWindow->m_needsInvalidateShadow = true; +} + /*! Flushes the given \a region from the specified \a window onto the screen. @@ -217,6 +235,7 @@ void QNSWindowBackingStore::flush(QWindow *window, const QRegion ®ion, const QCocoaWindow *topLevelCocoaWindow = static_cast<QCocoaWindow *>(topLevelWindow->handle()); if (Q_UNLIKELY(topLevelCocoaWindow->m_needsInvalidateShadow)) { + qCDebug(lcQpaBackingStore) << "Invalidating window shadow for" << topLevelCocoaWindow; [topLevelView.window invalidateShadow]; topLevelCocoaWindow->m_needsInvalidateShadow = false; } @@ -382,10 +401,11 @@ void QCALayerBackingStore::ensureBackBuffer() bool QCALayerBackingStore::recreateBackBufferIfNeeded() { - const qreal devicePixelRatio = window()->devicePixelRatio(); + const QCocoaWindow *platformWindow = static_cast<QCocoaWindow *>(window()->handle()); + const qreal devicePixelRatio = platformWindow->devicePixelRatio(); QSize requestedBufferSize = m_requestedSize * devicePixelRatio; - const NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view(); + const NSView *backingStoreView = platformWindow->view(); Q_UNUSED(backingStoreView); auto bufferSizeMismatch = [&](const QSize requested, const QSize actual) { diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h index 9771cd0289..69587a24be 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h @@ -191,6 +191,7 @@ public: static void waitingObserverCallback(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); static void firstLoopEntry(CFRunLoopObserverRef ref, CFRunLoopActivity activity, void *info); + bool sendQueuedUserInputEvents(); void processPostedEvents(); }; diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm index 84ffadea83..d3bb0711f0 100644 --- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm +++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm @@ -377,16 +377,9 @@ bool QCocoaEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags) NSEvent* event = nil; // First, send all previously excluded input events, if any: - if (!excludeUserEvents) { - while (!d->queuedUserInputEvents.isEmpty()) { - event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst()); - if (!filterNativeEvent("NSEvent", event, nullptr)) { - [NSApp sendEvent:event]; - retVal = true; - } - [event release]; - } - } + if (d->sendQueuedUserInputEvents()) + retVal = true; + // If Qt is used as a plugin, or as an extension in a native cocoa // application, we should not run or stop NSApplication; This will be @@ -843,6 +836,23 @@ void QCocoaEventDispatcherPrivate::waitingObserverCallback(CFRunLoopObserverRef, emit static_cast<QCocoaEventDispatcher*>(info)->awake(); } +bool QCocoaEventDispatcherPrivate::sendQueuedUserInputEvents() +{ + Q_Q(QCocoaEventDispatcher); + if (processEventsFlags & QEventLoop::ExcludeUserInputEvents) + return false; + bool didSendEvent = false; + while (!queuedUserInputEvents.isEmpty()) { + NSEvent *event = static_cast<NSEvent *>(queuedUserInputEvents.takeFirst()); + if (!q->filterNativeEvent("NSEvent", event, nullptr)) { + [NSApp sendEvent:event]; + didSendEvent = true; + } + [event release]; + } + return didSendEvent; +} + void QCocoaEventDispatcherPrivate::processPostedEvents() { if (blockSendPostedEvents) { @@ -896,6 +906,7 @@ void QCocoaEventDispatcherPrivate::postedEventsSourceCallback(void *info) d->maybeCancelWaitForMoreEvents(); return; } + d->sendQueuedUserInputEvents(); d->processPostedEvents(); d->maybeCancelWaitForMoreEvents(); } diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.h b/src/plugins/platforms/cocoa/qcocoaglcontext.h index eefb1cd0fb..c1041ac2da 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.h +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.h @@ -80,7 +80,7 @@ private: NSOpenGLContext *m_shareContext = nil; QSurfaceFormat m_format; bool m_didCheckForSoftwareContext = false; - QVarLengthArray<QMacScopedObserver, 3> m_updateObservers; + QVarLengthArray<QMacNotificationObserver, 3> m_updateObservers; QAtomicInt m_needsUpdate = false; }; diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm index fe1fc31553..0f8fec0548 100644 --- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm +++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm @@ -404,13 +404,13 @@ bool QCocoaGLContext::setDrawable(QPlatformSurface *surface) m_updateObservers.clear(); if (view.layer) { - m_updateObservers.append(QMacScopedObserver(view, NSViewFrameDidChangeNotification, updateCallback)); - m_updateObservers.append(QMacScopedObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view.window, NSWindowDidChangeScreenNotification, updateCallback)); } else { - m_updateObservers.append(QMacScopedObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); + m_updateObservers.append(QMacNotificationObserver(view, NSViewGlobalFrameDidChangeNotification, updateCallback)); } - m_updateObservers.append(QMacScopedObserver([NSApplication sharedApplication], + m_updateObservers.append(QMacNotificationObserver([NSApplication sharedApplication], NSApplicationDidChangeScreenParametersNotification, updateCallback)); // If any of the observers fire at this point it's fine. We check the diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm index 1b184cd60f..c9eafa81d0 100644 --- a/src/plugins/platforms/cocoa/qcocoahelpers.mm +++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm @@ -297,13 +297,12 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum) */ Qt::MouseButton cocoaButton2QtButton(NSEvent *event) { - switch (event.type) { - case NSEventTypeMouseMoved: + if (cocoaEvent2QtMouseEvent(event) == QEvent::MouseMove) return Qt::NoButton; + switch (event.type) { case NSEventTypeRightMouseUp: case NSEventTypeRightMouseDown: - case NSEventTypeRightMouseDragged: return Qt::RightButton; default: diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm index 300082d694..08e7447a75 100644 --- a/src/plugins/platforms/cocoa/qcocoaintegration.mm +++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm @@ -215,6 +215,25 @@ QCocoaIntegration::QCocoaIntegration(const QStringList ¶mList) connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &QCocoaIntegration::focusWindowChanged); + + static auto splashScreenHider = QMacKeyValueObserver(NSApp, @"modalWindow", []{ + const QWindowList allWindows = QGuiApplication::topLevelWindows(); + for (QWindow *window : allWindows) { + if ((window->flags() & Qt::SplashScreen) == Qt::SplashScreen) { + QCocoaWindow *platformWindow = static_cast<QCocoaWindow*>(window->handle()); + NSWindow *splashWindow = platformWindow->view().window; + if (!splashWindow) + continue; + if (NSApp.modalWindow) { + NSInteger originalLevel = splashWindow.level; + splashWindow.level = NSNormalWindowLevel; + window->setProperty("_q_levelBeforeModalSession", (qlonglong)originalLevel); + } else if (NSInteger originalLevel = window->property("_q_levelBeforeModalSession").toLongLong()) { + splashWindow.level = originalLevel; + } + } + } + }); } QCocoaIntegration::~QCocoaIntegration() diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h index 34d8428188..a957710a88 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.h +++ b/src/plugins/platforms/cocoa/qcocoamenu.h @@ -92,6 +92,9 @@ public: bool isOpen() const; void setIsOpen(bool isOpen); + bool isAboutToShow() const; + void setIsAboutToShow(bool isAbout); + void timerEvent(QTimerEvent *e) override; void syncMenuItem_helper(QPlatformMenuItem *menuItem, bool menubarUpdate); @@ -111,6 +114,7 @@ private: bool m_parentEnabled:1; bool m_visible:1; bool m_isOpen:1; + bool m_isAboutToShow:1; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm index f34988721d..8c4fca0d29 100644 --- a/src/plugins/platforms/cocoa/qcocoamenu.mm +++ b/src/plugins/platforms/cocoa/qcocoamenu.mm @@ -178,6 +178,16 @@ void QCocoaMenu::setIsOpen(bool isOpen) m_isOpen = isOpen; } +bool QCocoaMenu::isAboutToShow() const +{ + return m_isAboutToShow; +} + +void QCocoaMenu::setIsAboutToShow(bool isAbout) +{ + m_isAboutToShow = isAbout; +} + void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem) { QMacAutoReleasePool pool; diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm index 32fc3ab660..c35cf6d799 100644 --- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm +++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm @@ -141,6 +141,12 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) if (menu == m_menu) return; + bool setAttached = false; + if ([m_native.menu isKindOfClass:[QCocoaNSMenu class]]) { + auto parentMenu = static_cast<QCocoaNSMenu *>(m_native.menu); + setAttached = parentMenu.platformMenu && parentMenu.platformMenu->isAboutToShow(); + } + if (m_menu && m_menu->menuParent() == this) { m_menu->setMenuParent(nullptr); // Free the menu from its parent's influence @@ -154,6 +160,8 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu) if (m_menu) { m_menu->setMenuParent(this); m_menu->propagateEnabledState(isEnabled()); + if (setAttached) + m_menu->setAttachedItem(m_native); } else { // we previously had a menu, but no longer // clear out our item so the nexy sync() call builds a new one diff --git a/src/plugins/platforms/cocoa/qcocoansmenu.mm b/src/plugins/platforms/cocoa/qcocoansmenu.mm index 65b0832d9f..c51460282a 100644 --- a/src/plugins/platforms/cocoa/qcocoansmenu.mm +++ b/src/plugins/platforms/cocoa/qcocoansmenu.mm @@ -195,7 +195,9 @@ static NSString *qt_mac_removePrivateUnicode(NSString *string) return; platformMenu->setIsOpen(true); + platformMenu->setIsAboutToShow(true); emit platformMenu->aboutToShow(); + platformMenu->setIsAboutToShow(false); } - (void)menuDidClose:(NSMenu *)menu diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h index c42fa7d2e8..788b616e78 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.h +++ b/src/plugins/platforms/cocoa/qcocoatheme.h @@ -45,6 +45,8 @@ Q_FORWARD_DECLARE_OBJC_CLASS(QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver)); +#include <QtCore/private/qcore_mac_p.h> + QT_BEGIN_NAMESPACE class QPalette; @@ -82,9 +84,10 @@ public: private: mutable QPalette *m_systemPalette; + QMacNotificationObserver m_systemColorObserver; mutable QHash<QPlatformTheme::Palette, QPalette*> m_palettes; mutable QHash<QPlatformTheme::Font, QFont*> m_fonts; - QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) *m_appearanceObserver; + QMacKeyValueObserver m_appearanceObserver; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm index efe670abed..7c10456824 100644 --- a/src/plugins/platforms/cocoa/qcocoatheme.mm +++ b/src/plugins/platforms/cocoa/qcocoatheme.mm @@ -80,70 +80,32 @@ #include <CoreServices/CoreServices.h> -#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) -@interface QT_MANGLE_NAMESPACE(QCocoaThemeAppAppearanceObserver) : NSObject -@property (readonly, nonatomic) QCocoaTheme *theme; -- (instancetype)initWithTheme:(QCocoaTheme *)theme; -@end - -QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaThemeAppAppearanceObserver); - -@implementation QCocoaThemeAppAppearanceObserver -- (instancetype)initWithTheme:(QCocoaTheme *)theme -{ - if ((self = [super init])) { - _theme = theme; - [NSApp addObserver:self forKeyPath:@"effectiveAppearance" options:NSKeyValueObservingOptionNew context:nullptr]; - } - return self; -} - -- (void)dealloc -{ - [NSApp removeObserver:self forKeyPath:@"effectiveAppearance"]; - [super dealloc]; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object - change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context -{ - Q_UNUSED(change); - Q_UNUSED(context); - - Q_ASSERT(object == NSApp); - Q_ASSERT([keyPath isEqualToString:@"effectiveAppearance"]); - - if (__builtin_available(macOS 10.14, *)) - NSAppearance.currentAppearance = NSApp.effectiveAppearance; - - self.theme->handleSystemThemeChange(); -} -@end -#endif // QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) - QT_BEGIN_NAMESPACE const char *QCocoaTheme::name = "cocoa"; QCocoaTheme::QCocoaTheme() - : m_systemPalette(nullptr), m_appearanceObserver(nil) + : m_systemPalette(nullptr) { #if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) - m_appearanceObserver = [[QCocoaThemeAppAppearanceObserver alloc] initWithTheme:this]; + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSMojave) { + m_appearanceObserver = QMacKeyValueObserver(NSApp, @"effectiveAppearance", [this] { + if (__builtin_available(macOS 10.14, *)) + NSAppearance.currentAppearance = NSApp.effectiveAppearance; + + handleSystemThemeChange(); + }); + } #endif - [[NSNotificationCenter defaultCenter] addObserverForName:NSSystemColorsDidChangeNotification - object:nil queue:nil usingBlock:^(NSNotification *) { + m_systemColorObserver = QMacNotificationObserver(nil, + NSSystemColorsDidChangeNotification, [this] { handleSystemThemeChange(); - }]; + }); } QCocoaTheme::~QCocoaTheme() { - if (m_appearanceObserver) - [m_appearanceObserver release]; - reset(); qDeleteAll(m_fonts); } diff --git a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm index b00fde6c6f..7ce78ee738 100644 --- a/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm +++ b/src/plugins/platforms/cocoa/qcocoavulkaninstance.mm @@ -54,7 +54,7 @@ QCocoaVulkanInstance::~QCocoaVulkanInstance() void QCocoaVulkanInstance::createOrAdoptInstance() { - initInstance(m_instance, QByteArrayList()); + initInstance(m_instance, QByteArrayList() << QByteArrayLiteral("VK_MVK_macos_surface")); } VkSurfaceKHR *QCocoaVulkanInstance::createSurface(QWindow *window) diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index 67b0cbdfe9..363a026e71 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -1011,16 +1011,16 @@ void QCocoaWindow::setMask(const QRegion ®ion) } else { m_view.layer.mask = nil; } - } - - if (isContentView()) { - // Setting the mask requires invalidating the NSWindow shadow, but that needs - // to happen after the backingstore has been redrawn, so that AppKit can pick - // up the new window shape based on the backingstore content. Doing a display - // directly here is not an option, as the window might not be exposed at this - // time, and so would not result in an updated backingstore. - m_needsInvalidateShadow = true; - [m_view setNeedsDisplay:YES]; + } else { + if (isContentView()) { + // Setting the mask requires invalidating the NSWindow shadow, but that needs + // to happen after the backingstore has been redrawn, so that AppKit can pick + // up the new window shape based on the backingstore content. Doing a display + // directly here is not an option, as the window might not be exposed at this + // time, and so would not result in an updated backingstore. + m_needsInvalidateShadow = true; + [m_view setNeedsDisplay:YES]; + } } } diff --git a/src/plugins/platforms/cocoa/qnsview_mouse.mm b/src/plugins/platforms/cocoa/qnsview_mouse.mm index 4408385aa8..7c566442f0 100644 --- a/src/plugins/platforms/cocoa/qnsview_mouse.mm +++ b/src/plugins/platforms/cocoa/qnsview_mouse.mm @@ -282,20 +282,19 @@ nativeDrag->setLastMouseEvent(theEvent, self); const auto modifiers = [QNSView convertKeyModifiers:theEvent.modifierFlags]; - const auto buttons = currentlyPressedMouseButtons(); auto button = cocoaButton2QtButton(theEvent); if (button == Qt::LeftButton && m_sendUpAsRightButton) button = Qt::RightButton; const auto eventType = cocoaEvent2QtMouseEvent(theEvent); if (eventType == QEvent::MouseMove) - qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << buttons; + qCDebug(lcQpaMouse) << eventType << "at" << qtWindowPoint << "with" << m_buttons; else - qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << buttons; + qCInfo(lcQpaMouse) << eventType << "of" << button << "at" << qtWindowPoint << "with" << m_buttons; QWindowSystemInterface::handleMouseEvent(targetView->m_platformWindow->window(), timestamp, qtWindowPoint, qtScreenPoint, - buttons, button, eventType, modifiers); + m_buttons, button, eventType, modifiers); } - (bool)handleMouseDownEvent:(NSEvent *)theEvent diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h index babe646fd8..6d880e24cf 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dhelpers.h @@ -69,12 +69,15 @@ inline D2D1_RECT_F to_d2d_rect_f(const QRectF &qrect) inline D2D1_SIZE_U to_d2d_size_u(const QSizeF &qsize) { - return D2D1::SizeU(qsize.width(), qsize.height()); + + return D2D1::SizeU(UINT32(qRound(qsize.width())), + UINT32(qRound(qsize.height()))); } inline D2D1_SIZE_U to_d2d_size_u(const QSize &qsize) { - return D2D1::SizeU(qsize.width(), qsize.height()); + return D2D1::SizeU(UINT32(qsize.width()), + UINT32(qsize.height())); } inline D2D1_POINT_2F to_d2d_point_2f(const QPointF &qpoint) diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp index 86c863ec50..e074f87eb4 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.cpp @@ -51,22 +51,11 @@ #include <QtCore/qversionnumber.h> #include <QtGui/private/qpixmap_raster_p.h> #include <QtGui/qpa/qwindowsysteminterface.h> -#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h> #include <QVarLengthArray> QT_BEGIN_NAMESPACE -class QWindowsDirect2DEventDispatcher : public QWindowsGuiEventDispatcher -{ -public: - QWindowsDirect2DEventDispatcher(QObject *parent = nullptr) - : QWindowsGuiEventDispatcher(parent) - { - uninstallMessageHook(); // ### Workaround for QTBUG-42428 - } -}; - class QWindowsDirect2DIntegrationPrivate { public: @@ -91,7 +80,7 @@ static QVersionNumber systemD2DVersion() if (VerQueryValue(info.constData(), __TEXT("\\"), reinterpret_cast<void **>(&fi), &size) && size) { - const VS_FIXEDFILEINFO *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi); + const auto *verInfo = reinterpret_cast<const VS_FIXEDFILEINFO *>(fi); return QVersionNumber{HIWORD(verInfo->dwFileVersionMS), LOWORD(verInfo->dwFileVersionMS), HIWORD(verInfo->dwFileVersionLS), LOWORD(verInfo->dwFileVersionLS)}; } @@ -140,7 +129,7 @@ QWindowsDirect2DIntegration *QWindowsDirect2DIntegration::create(const QStringLi return nullptr; } - QWindowsDirect2DIntegration *integration = new QWindowsDirect2DIntegration(paramList); + auto *integration = new QWindowsDirect2DIntegration(paramList); if (!integration->init()) { delete integration; @@ -188,11 +177,6 @@ QPlatformBackingStore *QWindowsDirect2DIntegration::createPlatformBackingStore(Q return new QWindowsDirect2DBackingStore(window); } -QAbstractEventDispatcher *QWindowsDirect2DIntegration::createEventDispatcher() const -{ - return new QWindowsDirect2DEventDispatcher; -} - QWindowsDirect2DContext *QWindowsDirect2DIntegration::direct2DContext() const { return &d->m_d2dContext; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h index 19c7521eb7..5ea36e04bc 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dintegration.h @@ -61,7 +61,6 @@ public: QPlatformNativeInterface *nativeInterface() const override; QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const override; QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const override; - QAbstractEventDispatcher *createEventDispatcher() const override; QWindowsDirect2DContext *direct2DContext() const; diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp index 1b82db0b37..d7aba66b2f 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dpaintengine.cpp @@ -253,7 +253,7 @@ struct D2DVectorPathCache { static void cleanup_func(QPaintEngineEx *engine, void *data) { Q_UNUSED(engine); - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(data); + auto *e = static_cast<D2DVectorPathCache *>(data); delete e; } }; @@ -689,7 +689,7 @@ public: *needsEmulation = true; } else { ComPtr<ID2D1LinearGradientBrush> linear; - const QLinearGradient *qlinear = static_cast<const QLinearGradient *>(newBrush.gradient()); + const auto *qlinear = static_cast<const QLinearGradient *>(newBrush.gradient()); D2D1_LINEAR_GRADIENT_BRUSH_PROPERTIES linearGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; @@ -727,7 +727,7 @@ public: *needsEmulation = true; } else { ComPtr<ID2D1RadialGradientBrush> radial; - const QRadialGradient *qradial = static_cast<const QRadialGradient *>(newBrush.gradient()); + const auto *qradial = static_cast<const QRadialGradient *>(newBrush.gradient()); D2D1_RADIAL_GRADIENT_BRUSH_PROPERTIES radialGradientBrushProperties; ComPtr<ID2D1GradientStopCollection> gradientStopCollection; @@ -807,7 +807,7 @@ public: : nullptr; if (cacheEntry) { - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); + auto *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); if (alias && e->aliased) return e->aliased; else if (!alias && e->antiAliased) @@ -885,7 +885,7 @@ public: if (!cacheEntry) cacheEntry = path.addCacheData(q, new D2DVectorPathCache, D2DVectorPathCache::cleanup_func); - D2DVectorPathCache *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); + auto *e = static_cast<D2DVectorPathCache *>(cacheEntry->data); if (alias) e->aliased = geometry; else @@ -943,7 +943,11 @@ public: // Default path (no optimization) if (!(path.shape() == QVectorPath::LinesHint || path.shape() == QVectorPath::PolygonHint) - || !pen.dashBrush || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing)) { + || !pen.dashBrush +#if QT_DEPRECATED_SINCE(5, 14) + || q->state()->renderHints.testFlag(QPainter::HighQualityAntialiasing) +#endif + || q->state()->renderHints.testFlag(QPainter::Antialiasing)) { ComPtr<ID2D1Geometry> geometry = vectorPathToID2D1PathGeometry(path); if (!geometry) { qWarning("%s: Could not convert path to d2d geometry", __FUNCTION__); @@ -1481,7 +1485,7 @@ void QWindowsDirect2DPaintEngine::drawPixmap(const QRectF &r, return; } - QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); + auto *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(pm.handle()); QWindowsDirect2DBitmap *bitmap = pp->bitmap(); ensurePen(); @@ -1593,7 +1597,7 @@ void QWindowsDirect2DPaintEngine::drawTextItem(const QPointF &p, const QTextItem Q_D(QWindowsDirect2DPaintEngine); D2D_TAG(D2DDebugDrawTextItemTag); - const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); + const auto &ti = static_cast<const QTextItemInt &>(textItem); if (ti.glyphs.numGlyphs == 0) return; @@ -1686,7 +1690,7 @@ void QWindowsDirect2DPaintEngine::rasterFill(const QVectorPath &path, const QBru p.setBrush(state()->brush); p.setPen(state()->pen); - QPaintEngineEx *extended = static_cast<QPaintEngineEx *>(engine); + auto *extended = static_cast<QPaintEngineEx *>(engine); for (const QPainterClipInfo &info : qAsConst(state()->clipInfo)) { extended->state()->matrix = info.matrix; extended->transformChanged(); diff --git a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp index 239e5f3087..c417daaeae 100644 --- a/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp +++ b/src/plugins/platforms/direct2d/qwindowsdirect2dwindow.cpp @@ -310,7 +310,7 @@ void QWindowsDirect2DWindow::setupBitmap() QWindowsDirect2DPaintEngine::Flags flags = QWindowsDirect2DPaintEngine::NoFlag; if (!m_directRendering) flags |= QWindowsDirect2DPaintEngine::TranslucentTopLevelWindow; - QWindowsDirect2DPlatformPixmap *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType, + auto *pp = new QWindowsDirect2DPlatformPixmap(QPlatformPixmap::PixmapType, flags, m_bitmap.data()); m_pixmap.reset(new QPixmap(pp)); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp index 2e84915c80..07b2de7c58 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_x11/qeglfsx11integration.cpp @@ -66,7 +66,7 @@ QAtomicInt running; void EventReader::run() { xcb_generic_event_t *event = nullptr; - while (running.load() && (event = xcb_wait_for_event(m_integration->connection()))) { + while (running.loadRelaxed() && (event = xcb_wait_for_event(m_integration->connection()))) { uint response_type = event->response_type & ~0x80; switch (response_type) { case XCB_CLIENT_MESSAGE: { diff --git a/src/plugins/platforms/ios/quiview_accessibility.mm b/src/plugins/platforms/ios/quiview_accessibility.mm index a3f4156a59..458ddcc9b8 100644 --- a/src/plugins/platforms/ios/quiview_accessibility.mm +++ b/src/plugins/platforms/ios/quiview_accessibility.mm @@ -101,6 +101,8 @@ - (id)accessibilityElementAtIndex:(NSInteger)index { [self initAccessibility]; + if (index >= [m_accessibleElements count]) + return nil; return m_accessibleElements[index]; } @@ -110,4 +112,10 @@ return [m_accessibleElements indexOfObject:element]; } +- (NSArray *)accessibilityElements +{ + [self initAccessibility]; + return m_accessibleElements; +} + @end diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.cpp b/src/plugins/platforms/wasm/qwasmbackingstore.cpp index 5b40c44807..e8eda2605f 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.cpp +++ b/src/plugins/platforms/wasm/qwasmbackingstore.cpp @@ -55,6 +55,12 @@ QWasmBackingStore::~QWasmBackingStore() { } +void QWasmBackingStore::destroy() +{ + if (m_texture->isCreated()) + m_texture->destroy(); +} + QPaintDevice *QWasmBackingStore::paintDevice() { return &m_image; diff --git a/src/plugins/platforms/wasm/qwasmbackingstore.h b/src/plugins/platforms/wasm/qwasmbackingstore.h index 6ffa262e3d..4bca83c457 100644 --- a/src/plugins/platforms/wasm/qwasmbackingstore.h +++ b/src/plugins/platforms/wasm/qwasmbackingstore.h @@ -44,6 +44,7 @@ class QWasmBackingStore : public QPlatformBackingStore public: QWasmBackingStore(QWasmCompositor *compositor, QWindow *window); ~QWasmBackingStore(); + void destroy(); QPaintDevice *paintDevice() override; diff --git a/src/plugins/platforms/wasm/qwasmcompositor.cpp b/src/plugins/platforms/wasm/qwasmcompositor.cpp index e6a69c4814..6d211667be 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.cpp +++ b/src/plugins/platforms/wasm/qwasmcompositor.cpp @@ -37,6 +37,7 @@ #include <QtGui/qopenglcontext.h> #include <QtGui/qopenglfunctions.h> #include <QtGui/qopengltextureblitter.h> +#include <QtGui/qoffscreensurface.h> #include <QtGui/qpainter.h> #include <private/qpixmapcache_p.h> @@ -71,6 +72,28 @@ QWasmCompositor::QWasmCompositor(QWasmScreen *screen) QWasmCompositor::~QWasmCompositor() { delete m_frameBuffer; + destroy(); +} + +void QWasmCompositor::destroy() +{ + // Destroy OpenGL resources. This is done here in a separate function + // which can be called while screen() still returns a valid screen + // (which it might not, during destruction). A valid QScreen is + // a requirement for QOffscreenSurface on Wasm since the native + // context is tied to a single canvas. + if (m_context) { + QOffscreenSurface offScreenSurface(screen()->screen()); + offScreenSurface.setFormat(m_context->format()); + offScreenSurface.create(); + m_context->makeCurrent(&offScreenSurface); + for (QWasmWindow *window : m_windowStack) + window->destroy(); + m_blitter.reset(nullptr); + m_context.reset(nullptr); + } + + m_isEnabled = false; // prevent frame() from creating a new m_context } void QWasmCompositor::setEnabled(bool enabled) @@ -251,10 +274,13 @@ void QWasmCompositor::blit(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, void QWasmCompositor::drawWindowContent(QOpenGLTextureBlitter *blitter, QWasmScreen *screen, QWasmWindow *window) { QWasmBackingStore *backingStore = window->backingStore(); + if (!backingStore) + return; QOpenGLTexture const *texture = backingStore->getUpdatedTexture(); - - blit(blitter, screen, texture, window->geometry()); + QPoint windowCanvasPosition = window->geometry().topLeft() - screen->geometry().topLeft(); + QRect windowCanvasGeometry = QRect(windowCanvasPosition, window->geometry().size()); + blit(blitter, screen, texture, windowCanvasGeometry); } QPalette QWasmCompositor::makeWindowPalette() @@ -650,7 +676,7 @@ void QWasmCompositor::frame() m_needComposit = false; - if (m_windowStack.empty() || !screen()) + if (!m_isEnabled || m_windowStack.empty() || !screen()) return; QWasmWindow *someWindow = nullptr; @@ -673,7 +699,9 @@ void QWasmCompositor::frame() m_context->create(); } - m_context->makeCurrent(someWindow->window()); + bool ok = m_context->makeCurrent(someWindow->window()); + if (!ok) + return; if (!m_blitter->isCreated()) m_blitter->create(); diff --git a/src/plugins/platforms/wasm/qwasmcompositor.h b/src/plugins/platforms/wasm/qwasmcompositor.h index 3104573073..98f4a79b27 100644 --- a/src/plugins/platforms/wasm/qwasmcompositor.h +++ b/src/plugins/platforms/wasm/qwasmcompositor.h @@ -64,6 +64,7 @@ class QWasmCompositor : public QObject public: QWasmCompositor(QWasmScreen *screen); ~QWasmCompositor(); + void destroy(); enum QWasmSubControl { SC_None = 0x00000000, diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp index 6a02a457a0..3895646b89 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.cpp +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.cpp @@ -337,8 +337,6 @@ QWasmEventTranslator::QWasmEventTranslator(QWasmScreen *screen) void QWasmEventTranslator::initEventHandlers() { - qDebug() << "QWasmEventTranslator::initEventHandlers"; - QByteArray _canvasId = screen()->canvasId().toUtf8(); const char *canvasId = _canvasId.constData(); @@ -377,9 +375,6 @@ void QWasmEventTranslator::initEventHandlers() emscripten_set_touchend_callback(canvasId, (void *)this, 1, &touchCallback); emscripten_set_touchmove_callback(canvasId, (void *)this, 1, &touchCallback); emscripten_set_touchcancel_callback(canvasId, (void *)this, 1, &touchCallback); - - emscripten_set_resize_callback(nullptr, (void *)this, 1, uiEvent_cb); // Note: handles browser window resize - } template <typename Event> @@ -557,9 +552,12 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven Qt::KeyboardModifiers modifiers = translateMouseEventModifier(mouseEvent); QWindow *window2 = screen()->compositor()->windowAt(globalPoint, 5); - if (window2 == nullptr) - return; - lastWindow = window2; + + if (window2 == nullptr) { + window2 = lastWindow; + } else { + lastWindow = window2; + } QPoint localPoint = window2->mapFromGlobal(globalPoint); bool interior = window2->geometry().contains(globalPoint); @@ -621,7 +619,7 @@ void QWasmEventTranslator::processMouse(int eventType, const EmscriptenMouseEven } if (resizeMode != QWasmWindow::ResizeNone && !(htmlWindow->m_windowState & Qt::WindowFullScreen)) { - QPoint delta = QPoint(mouseEvent->canvasX, mouseEvent->canvasY) - resizePoint; + QPoint delta = QPoint(mouseEvent->targetX, mouseEvent->targetY) - resizePoint; resizeWindow(draggedWindow, resizeMode, resizeStartRect, delta); } } @@ -911,19 +909,4 @@ bool QWasmEventTranslator::processKeyboard(int eventType, const EmscriptenKeyboa return accepted; } -int QWasmEventTranslator::uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData) -{ - Q_UNUSED(e) - QWasmEventTranslator *eventTranslator = static_cast<QWasmEventTranslator *>(userData); - - if (eventType == EMSCRIPTEN_EVENT_RESIZE) { - // This resize event is called when the HTML window is resized. Depending - // on the page layout the the canvas might also have been resized, so we - // update the Qt screen size (and canvas render size). - eventTranslator->screen()->updateQScreenAndCanvasRenderSize(); - } - - return 0; -} - QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmeventtranslator.h b/src/plugins/platforms/wasm/qwasmeventtranslator.h index d6043072ba..1655b7226a 100644 --- a/src/plugins/platforms/wasm/qwasmeventtranslator.h +++ b/src/plugins/platforms/wasm/qwasmeventtranslator.h @@ -57,8 +57,6 @@ public: static int touchCallback(int eventType, const EmscriptenTouchEvent *ev, void *userData); - static int uiEvent_cb(int eventType, const EmscriptenUiEvent *e, void *userData); - void processEvents(); void initEventHandlers(); int handleTouch(int eventType, const EmscriptenTouchEvent *touchEvent); diff --git a/src/plugins/platforms/wasm/qwasmintegration.cpp b/src/plugins/platforms/wasm/qwasmintegration.cpp index 31b9104de1..116612c286 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.cpp +++ b/src/plugins/platforms/wasm/qwasmintegration.cpp @@ -35,6 +35,7 @@ #include "qwasmtheme.h" #include "qwasmclipboard.h" #include "qwasmservices.h" +#include "qwasmoffscreensurface.h" #include "qwasmwindow.h" #ifndef QT_NO_OPENGL @@ -123,6 +124,21 @@ QWasmIntegration::QWasmIntegration() } emscripten::val::global("window").set("onbeforeunload", val::module_property("qtBrowserBeforeUnload")); + + // install browser window resize handler + auto onWindowResize = [](int eventType, const EmscriptenUiEvent *e, void *userData) -> int { + Q_UNUSED(eventType); + Q_UNUSED(e); + Q_UNUSED(userData); + + // This resize event is called when the HTML window is resized. Depending + // on the page layout the the canvas(es) might also have been resized, so we + // update the Qt screen sizes (and canvas render sizes). + if (QWasmIntegration *integration = QWasmIntegration::get()) + integration->resizeAllScreens(); + return 0; + }; + emscripten_set_resize_callback(nullptr, nullptr, 1, onWindowResize); } QWasmIntegration::~QWasmIntegration() @@ -193,6 +209,11 @@ QPlatformInputContext *QWasmIntegration::inputContext() const return m_inputContext.data(); } +QPlatformOffscreenSurface *QWasmIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const +{ + return new QWasmOffscrenSurface(surface); +} + QPlatformFontDatabase *QWasmIntegration::fontDatabase() const { if (m_fontDb == nullptr) @@ -257,7 +278,9 @@ void QWasmIntegration::addScreen(const QString &canvasId) void QWasmIntegration::removeScreen(const QString &canvasId) { - QWindowSystemInterface::handleScreenRemoved(m_screens.take(canvasId)); + QWasmScreen *exScreen = m_screens.take(canvasId); + exScreen->destroy(); // clean up before deleting the screen + QWindowSystemInterface::handleScreenRemoved(exScreen); } void QWasmIntegration::resizeScreen(const QString &canvasId) @@ -275,4 +298,11 @@ void QWasmIntegration::updateDpi() QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(screen->screen(), dpiValue, dpiValue); } +void QWasmIntegration::resizeAllScreens() +{ + qDebug() << "resizeAllScreens"; + for (QWasmScreen *screen : m_screens) + screen->updateQScreenAndCanvasRenderSize(); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/wasm/qwasmintegration.h b/src/plugins/platforms/wasm/qwasmintegration.h index c04c0eaecc..2102f5c226 100644 --- a/src/plugins/platforms/wasm/qwasmintegration.h +++ b/src/plugins/platforms/wasm/qwasmintegration.h @@ -66,6 +66,7 @@ public: #ifndef QT_NO_OPENGL QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const override; #endif + QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const override; QPlatformFontDatabase *fontDatabase() const override; QAbstractEventDispatcher *createEventDispatcher() const override; QVariant styleHint(QPlatformIntegration::StyleHint hint) const override; @@ -85,6 +86,7 @@ public: void addScreen(const QString &canvasId); void removeScreen(const QString &canvasId); void resizeScreen(const QString &canvasId); + void resizeAllScreens(); void updateDpi(); private: diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp new file mode 100644 index 0000000000..a205e5ddea --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwasmoffscreensurface.h" + +QWasmOffscrenSurface::QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface) + :QPlatformOffscreenSurface(offscreenSurface) +{ + +} + +QWasmOffscrenSurface::~QWasmOffscrenSurface() +{ + +} diff --git a/src/plugins/platforms/wasm/qwasmoffscreensurface.h b/src/plugins/platforms/wasm/qwasmoffscreensurface.h new file mode 100644 index 0000000000..9d3e805be0 --- /dev/null +++ b/src/plugins/platforms/wasm/qwasmoffscreensurface.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWASMOFFSCREENSURFACE_H +#define QWASMOFFSCREENSURFACE_H + +#include <qpa/qplatformoffscreensurface.h> + +QT_BEGIN_NAMESPACE + +class QOffscreenSurface; +class QWasmOffscrenSurface : public QPlatformOffscreenSurface +{ +public: + explicit QWasmOffscrenSurface(QOffscreenSurface *offscreenSurface); + ~QWasmOffscrenSurface(); +private: + +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp index 1658f32f9e..62087f54bd 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp @@ -49,40 +49,31 @@ QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format) QWasmOpenGLContext::~QWasmOpenGLContext() { - if (m_context) + if (m_context) { emscripten_webgl_destroy_context(m_context); + m_context = 0; + } } -void QWasmOpenGLContext::maybeRecreateEmscriptenContext(QPlatformSurface *surface) +bool QWasmOpenGLContext::maybeCreateEmscriptenContext(QPlatformSurface *surface) { - // Native emscripten contexts are tied to a single surface. Recreate - // the context if the surface is changed. - if (surface != m_surface) { - m_surface = surface; - - // Destroy existing context - if (m_context) - emscripten_webgl_destroy_context(m_context); - - // Create new context - const QString canvasId = QWasmScreen::get(surface->screen())->canvasId(); - m_context = createEmscriptenContext(canvasId, m_requestedFormat); - - // Register context-lost callback. - auto callback = [](int eventType, const void *reserved, void *userData) -> EM_BOOL - { - Q_UNUSED(eventType); - Q_UNUSED(reserved); - // The application may get contex-lost if e.g. moved to the background. Set - // m_contextLost which will make isValid() return false. Application code will - // then detect this and recrate the the context, resulting in a new QWasmOpenGLContext - // instance. - reinterpret_cast<QWasmOpenGLContext *>(userData)->m_contextLost = true; - return true; - }; - bool capture = true; - emscripten_set_webglcontextlost_callback(canvasId.toLocal8Bit().constData(), this, capture, callback); - } + // Native emscripten/WebGL contexts are tied to a single screen/canvas. The first + // call to this function creates a native canvas for the given screen, subsequent + // calls verify that the surface is on/off the same screen. + QPlatformScreen *screen = surface->screen(); + if (m_context && !screen) + return false; // Alternative: return true to support makeCurrent on QOffScreenSurface with + // no screen. However, Qt likes to substitute QGuiApplication::primaryScreen() + // for null screens, which foils this plan. + if (!screen) + return false; + if (m_context) + return m_screen == screen; + + QString canvasId = QWasmScreen::get(screen)->canvasId(); + m_context = createEmscriptenContext(canvasId, m_requestedFormat); + m_screen = screen; + return true; } EMSCRIPTEN_WEBGL_CONTEXT_HANDLE QWasmOpenGLContext::createEmscriptenContext(const QString &canvasId, QSurfaceFormat format) @@ -125,7 +116,9 @@ GLuint QWasmOpenGLContext::defaultFramebufferObject(QPlatformSurface *surface) c bool QWasmOpenGLContext::makeCurrent(QPlatformSurface *surface) { - maybeRecreateEmscriptenContext(surface); + bool ok = maybeCreateEmscriptenContext(surface); + if (!ok) + return false; return emscripten_webgl_make_context_current(m_context) == EMSCRIPTEN_RESULT_SUCCESS; } @@ -148,7 +141,9 @@ bool QWasmOpenGLContext::isSharing() const bool QWasmOpenGLContext::isValid() const { - return (m_contextLost == false); + // Note: we get isValid() calls before we see the surface and can + // create a native context, so no context is also a valid state. + return !m_context || !emscripten_is_webgl_context_lost(m_context); } QFunctionPointer QWasmOpenGLContext::getProcAddress(const char *procName) diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.h b/src/plugins/platforms/wasm/qwasmopenglcontext.h index 126b596a7e..d27007e8ea 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.h +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.h @@ -34,6 +34,7 @@ QT_BEGIN_NAMESPACE +class QPlatformScreen; class QWasmOpenGLContext : public QPlatformOpenGLContext { public: @@ -50,12 +51,11 @@ public: QFunctionPointer getProcAddress(const char *procName) override; private: - void maybeRecreateEmscriptenContext(QPlatformSurface *surface); + bool maybeCreateEmscriptenContext(QPlatformSurface *surface); static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE createEmscriptenContext(const QString &canvasId, QSurfaceFormat format); - bool m_contextLost = false; QSurfaceFormat m_requestedFormat; - QPlatformSurface *m_surface = nullptr; + QPlatformScreen *m_screen = nullptr; EMSCRIPTEN_WEBGL_CONTEXT_HANDLE m_context = 0; }; diff --git a/src/plugins/platforms/wasm/qwasmscreen.cpp b/src/plugins/platforms/wasm/qwasmscreen.cpp index af50ce7440..f2eabfa486 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.cpp +++ b/src/plugins/platforms/wasm/qwasmscreen.cpp @@ -58,7 +58,12 @@ QWasmScreen::QWasmScreen(const QString &canvasId) QWasmScreen::~QWasmScreen() { + destroy(); +} +void QWasmScreen::destroy() +{ + m_compositor->destroy(); } QWasmScreen *QWasmScreen::get(QPlatformScreen *screen) diff --git a/src/plugins/platforms/wasm/qwasmscreen.h b/src/plugins/platforms/wasm/qwasmscreen.h index 8d0d15f245..fcf693681c 100644 --- a/src/plugins/platforms/wasm/qwasmscreen.h +++ b/src/plugins/platforms/wasm/qwasmscreen.h @@ -52,6 +52,7 @@ class QWasmScreen : public QObject, public QPlatformScreen public: QWasmScreen(const QString &canvasId); ~QWasmScreen(); + void destroy(); static QWasmScreen *get(QPlatformScreen *screen); static QWasmScreen *get(QScreen *screen); diff --git a/src/plugins/platforms/wasm/qwasmwindow.cpp b/src/plugins/platforms/wasm/qwasmwindow.cpp index 39797cb09d..594db65cfd 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.cpp +++ b/src/plugins/platforms/wasm/qwasmwindow.cpp @@ -65,6 +65,12 @@ QWasmWindow::~QWasmWindow() m_compositor->removeWindow(this); } +void QWasmWindow::destroy() +{ + if (m_backingStore) + m_backingStore->destroy(); +} + void QWasmWindow::initialize() { QRect rect = windowGeometry(); diff --git a/src/plugins/platforms/wasm/qwasmwindow.h b/src/plugins/platforms/wasm/qwasmwindow.h index cbbce99aeb..a098172649 100644 --- a/src/plugins/platforms/wasm/qwasmwindow.h +++ b/src/plugins/platforms/wasm/qwasmwindow.h @@ -58,6 +58,7 @@ public: QWasmWindow(QWindow *w, QWasmCompositor *compositor, QWasmBackingStore *backingStore); ~QWasmWindow(); + void destroy(); void initialize() override; diff --git a/src/plugins/platforms/wasm/wasm.pro b/src/plugins/platforms/wasm/wasm.pro index e8728d9dba..c28df8f893 100644 --- a/src/plugins/platforms/wasm/wasm.pro +++ b/src/plugins/platforms/wasm/wasm.pro @@ -20,7 +20,8 @@ SOURCES = \ qwasmopenglcontext.cpp \ qwasmtheme.cpp \ qwasmclipboard.cpp \ - qwasmservices.cpp + qwasmservices.cpp \ + qwasmoffscreensurface.cpp HEADERS = \ qwasmintegration.h \ @@ -35,7 +36,8 @@ HEADERS = \ qwasmopenglcontext.h \ qwasmtheme.h \ qwasmclipboard.h \ - qwasmservices.h + qwasmservices.h \ + qwasmoffscreensurface.h wasmfonts.files = \ ../../../3rdparty/wasm/Vera.ttf \ diff --git a/src/plugins/platforms/windows/qwin10helpers.cpp b/src/plugins/platforms/windows/qwin10helpers.cpp index cc17d8798f..9a7fce9cd5 100644 --- a/src/plugins/platforms/windows/qwin10helpers.cpp +++ b/src/plugins/platforms/windows/qwin10helpers.cpp @@ -137,7 +137,7 @@ bool qt_windowsIsTabletMode(HWND hwnd) const wchar_t uiViewSettingsId[] = L"Windows.UI.ViewManagement.UIViewSettings"; HSTRING_HEADER uiViewSettingsIdRefHeader; HSTRING uiViewSettingsIdHs = nullptr; - const UINT32 uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); + const auto uiViewSettingsIdLen = UINT32(sizeof(uiViewSettingsId) / sizeof(uiViewSettingsId[0]) - 1); if (FAILED(baseComDll.windowsCreateStringReference(uiViewSettingsId, uiViewSettingsIdLen, &uiViewSettingsIdRefHeader, &uiViewSettingsIdHs))) return false; diff --git a/src/plugins/platforms/windows/qwindowsbackingstore.cpp b/src/plugins/platforms/windows/qwindowsbackingstore.cpp index 68807fabdd..bd7bdc55d1 100644 --- a/src/plugins/platforms/windows/qwindowsbackingstore.cpp +++ b/src/plugins/platforms/windows/qwindowsbackingstore.cpp @@ -158,7 +158,7 @@ void QWindowsBackingStore::resize(const QSize &size, const QRegion ®ion) format = qt_maybeAlphaVersionWithSameDepth(format); QWindowsNativeImage *oldwni = m_image.data(); - QWindowsNativeImage *newwni = new QWindowsNativeImage(size.width(), size.height(), format); + auto *newwni = new QWindowsNativeImage(size.width(), size.height(), format); if (oldwni && !region.isEmpty()) { const QImage &oldimg(oldwni->image()); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index e36a285aa2..f5b0dced93 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -77,6 +77,7 @@ #include <QtCore/qoperatingsystemversion.h> #include <QtCore/qsysinfo.h> #include <QtCore/qscopedpointer.h> +#include <QtCore/quuid.h> #include <QtCore/private/qsystemlibrary_p.h> #include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h> @@ -133,8 +134,8 @@ static inline bool useRTL_Extensions() #if QT_CONFIG(sessionmanager) static inline QWindowsSessionManager *platformSessionManager() { - QGuiApplicationPrivate *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); - QSessionManagerPrivate *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager)); + auto *guiPrivate = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *managerPrivate = static_cast<QSessionManagerPrivate*>(QObjectPrivate::get(guiPrivate->session_manager)); return static_cast<QWindowsSessionManager *>(managerPrivate->platformSessionManager); } @@ -317,6 +318,8 @@ QWindowsContext::~QWindowsContext() OleUninitialize(); d->m_screenManager.clearScreens(); // Order: Potentially calls back to the windows. + if (d->m_displayContext) + ReleaseDC(nullptr, d->m_displayContext); m_instance = nullptr; } @@ -542,10 +545,10 @@ QString QWindowsContext::registerWindowClass(QString cname, // each one has to have window class names with a unique name // The first instance gets the unmodified name; if the class // has already been registered by another instance of Qt then - // add an instance-specific ID, the address of the window proc. + // add a UUID. static int classExists = -1; - const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); + const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); if (classExists == -1) { WNDCLASS wcinfo; classExists = GetClassInfo(appInstance, reinterpret_cast<LPCWSTR>(cname.utf16()), &wcinfo); @@ -553,7 +556,7 @@ QString QWindowsContext::registerWindowClass(QString cname, } if (classExists) - cname += QString::number(reinterpret_cast<quintptr>(proc)); + cname += QUuid::createUuid().toString(); if (d->m_registeredWindowClassNames.contains(cname)) // already registered in our list return cname; @@ -598,7 +601,7 @@ QString QWindowsContext::registerWindowClass(QString cname, void QWindowsContext::unregisterWindowClasses() { - const HINSTANCE appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); + const auto appInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr)); for (const QString &name : qAsConst(d->m_registeredWindowClassNames)) { if (!UnregisterClass(reinterpret_cast<LPCWSTR>(name.utf16()), appInstance) && QWindowsContext::verbose) @@ -749,6 +752,12 @@ QWindowsWindow *QWindowsContext::findPlatformWindowAt(HWND parent, QWindowsWindow *result = nullptr; const POINT screenPoint = { screenPointIn.x(), screenPointIn.y() }; while (findPlatformWindowHelper(screenPoint, cwex_flags, this, &parent, &result)) {} + // QTBUG-40815: ChildWindowFromPointEx() can hit on special windows from + // screen recorder applications like ScreenToGif. Fall back to WindowFromPoint(). + if (result == nullptr) { + if (const HWND window = WindowFromPoint(screenPoint)) + result = findPlatformWindow(window); + } return result; } @@ -925,7 +934,7 @@ bool QWindowsContext::systemParametersInfo(unsigned action, unsigned param, void bool QWindowsContext::systemParametersInfoForScreen(unsigned action, unsigned param, void *out, const QPlatformScreen *screen) { - return systemParametersInfo(action, param, out, screen ? screen->logicalDpi().first : 0); + return systemParametersInfo(action, param, out, screen ? unsigned(screen->logicalDpi().first) : 0u); } bool QWindowsContext::systemParametersInfoForWindow(unsigned action, unsigned param, void *out, @@ -944,7 +953,8 @@ bool QWindowsContext::nonClientMetrics(NONCLIENTMETRICS *ncm, unsigned dpi) bool QWindowsContext::nonClientMetricsForScreen(NONCLIENTMETRICS *ncm, const QPlatformScreen *screen) { - return nonClientMetrics(ncm, screen ? screen->logicalDpi().first : 0); + const int dpi = screen ? qRound(screen->logicalDpi().first) : 0; + return nonClientMetrics(ncm, unsigned(dpi)); } bool QWindowsContext::nonClientMetricsForWindow(NONCLIENTMETRICS *ncm, const QPlatformWindow *win) @@ -1351,7 +1361,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, sessionManager->blocksInteraction(); sessionManager->clearCancellation(); - QGuiApplicationPrivate *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); qGuiAppPriv->commitData(); if (lParam & ENDSESSION_LOGOFF) @@ -1369,7 +1379,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, // we receive the message for each toplevel window included internal hidden ones, // but the aboutToQuit signal should be emitted only once. - QGuiApplicationPrivate *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); + auto *qGuiAppPriv = static_cast<QGuiApplicationPrivate*>(QObjectPrivate::get(qApp)); if (endsession && !qGuiAppPriv->aboutToQuitEmitted) { qGuiAppPriv->aboutToQuitEmitted = true; int index = QGuiApplication::staticMetaObject.indexOfSignal("aboutToQuit()"); diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp index 20a8117304..17e8cffb76 100644 --- a/src/plugins/platforms/windows/qwindowscursor.cpp +++ b/src/plugins/platforms/windows/qwindowscursor.cpp @@ -752,7 +752,7 @@ QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const && GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor) && bmColor.bmWidth == bmColor.bmWidthBytes / 4) { const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes; - uchar *colorBits = new uchar[colorBitsLength]; + auto *colorBits = new uchar[colorBitsLength]; GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits); const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight, bmColor.bmWidthBytes, QImage::Format_ARGB32); diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index 57f19b5ff2..b7ab952a1d 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -356,7 +356,7 @@ struct FindDialogContext static BOOL QT_WIN_CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam) { - FindDialogContext *context = reinterpret_cast<FindDialogContext *>(lParam); + auto *context = reinterpret_cast<FindDialogContext *>(lParam); DWORD winPid = 0; GetWindowThreadProcessId(hwnd, &winPid); if (winPid != context->processId) @@ -531,7 +531,7 @@ private: IFileDialogEvents *QWindowsNativeFileDialogEventHandler::create(QWindowsNativeFileDialogBase *nativeFileDialog) { IFileDialogEvents *result; - QWindowsNativeFileDialogEventHandler *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); + auto *eventHandler = new QWindowsNativeFileDialogEventHandler(nativeFileDialog); if (FAILED(eventHandler->QueryInterface(IID_IFileDialogEvents, reinterpret_cast<void **>(&result)))) { qErrnoWarning("Unable to obtain IFileDialogEvents"); return nullptr; @@ -1112,7 +1112,7 @@ void QWindowsNativeFileDialogBase::setDefaultSuffixSys(const QString &s) // If this parameter is non-empty, it will be appended by the dialog for the 'Any files' // filter ('*'). If this parameter is non-empty and the current filter has a suffix, // the dialog will append the filter's suffix. - wchar_t *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); + auto *wSuffix = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(s.utf16())); m_fileDialog->SetDefaultExtension(wSuffix); } @@ -1125,7 +1125,7 @@ static inline IFileDialog2 *getFileDialog2(IFileDialog *fileDialog) void QWindowsNativeFileDialogBase::setLabelText(QFileDialogOptions::DialogLabel l, const QString &text) { - wchar_t *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); + auto *wText = const_cast<wchar_t *>(reinterpret_cast<const wchar_t *>(text.utf16())); switch (l) { case QFileDialogOptions::FileName: m_fileDialog->SetFileNameLabel(wText); @@ -1770,7 +1770,7 @@ void QWindowsXpNativeFileDialog::doExec(HWND owner) static int QT_WIN_CALLBACK xpFileDialogGetExistingDirCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { - QWindowsXpNativeFileDialog *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData); + auto *dialog = reinterpret_cast<QWindowsXpNativeFileDialog *>(lpData); return dialog->existingDirCallback(hwnd, uMsg, lParam); } @@ -1843,7 +1843,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow const QList<FilterSpec> specs = filterSpecs(m_options->nameFilters(), m_options->options() & QFileDialogOptions::HideNameFilterDetails, &totalStringLength); const int size = specs.size(); - wchar_t *ptr = new wchar_t[totalStringLength + 2 * size + 1]; + auto *ptr = new wchar_t[totalStringLength + 2 * size + 1]; ofn->lpstrFilter = ptr; for (const FilterSpec &spec : specs) { ptr += spec.description.toWCharArray(ptr); diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp index 502c92ef59..3e4c93d47a 100644 --- a/src/plugins/platforms/windows/qwindowsdrag.cpp +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -627,7 +627,7 @@ QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, m_chosenEffect = DROPEFFECT_COPY; HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); if (hData) { - DWORD *moveEffect = reinterpret_cast<DWORD *>(GlobalLock(hData)); + auto *moveEffect = reinterpret_cast<DWORD *>(GlobalLock(hData)); *moveEffect = DROPEFFECT_MOVE; GlobalUnlock(hData); STGMEDIUM medium; @@ -704,9 +704,9 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag) DWORD resultEffect; QWindowsDrag::m_canceled = false; - QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(this); + auto *windowDropSource = new QWindowsOleDropSource(this); windowDropSource->createCursors(); - QWindowsDropDataObject *dropDataObject = new QWindowsDropDataObject(dropData); + auto *dropDataObject = new QWindowsDropDataObject(dropData); const Qt::DropActions possibleActions = drag->supportedActions(); const DWORD allowedEffects = translateToWinDragEffects(possibleActions); qCDebug(lcQpaMime) << '>' << __FUNCTION__ << "possible Actions=0x" diff --git a/src/plugins/platforms/windows/qwindowseglcontext.cpp b/src/plugins/platforms/windows/qwindowseglcontext.cpp index 063e81150e..e9f3dc5189 100644 --- a/src/plugins/platforms/windows/qwindowseglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowseglcontext.cpp @@ -469,10 +469,10 @@ bool QWindowsEGLContext::makeCurrent(QPlatformSurface *surface) QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); window->aboutToMakeCurrent(); int err = 0; - EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); + auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); if (eglSurface == EGL_NO_SURFACE) { if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; @@ -531,9 +531,9 @@ void QWindowsEGLContext::doneCurrent() void QWindowsEGLContext::swapBuffers(QPlatformSurface *surface) { QWindowsEGLStaticContext::libEGL.eglBindAPI(m_api); - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); int err = 0; - EGLSurface eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); + auto eglSurface = static_cast<EGLSurface>(window->surface(m_eglConfig, &err)); if (eglSurface == EGL_NO_SURFACE) { if (err == EGL_CONTEXT_LOST) { m_eglContext = EGL_NO_CONTEXT; diff --git a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp index 08e11c5e39..f2418b0e60 100644 --- a/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsgdinativeinterface.cpp @@ -50,7 +50,7 @@ void *QWindowsGdiNativeInterface::nativeResourceForBackingStore(const QByteArray qWarning("%s: '%s' requested for null backingstore or backingstore without handle.", __FUNCTION__, resource.constData()); return nullptr; } - QWindowsBackingStore *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); + auto *wbs = static_cast<QWindowsBackingStore *>(bs->handle()); if (resource == "getDC") return wbs->getDC(); qWarning("%s: Invalid key '%s' requested.", __FUNCTION__, resource.constData()); diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp index 66dd32d05e..24526bad2c 100644 --- a/src/plugins/platforms/windows/qwindowsglcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp @@ -1009,7 +1009,7 @@ QOpenGLStaticContext *QOpenGLStaticContext::create(bool softwareRendering) QScopedPointer<QOpenGLTemporaryContext> temporaryContext; if (!QOpenGLStaticContext::opengl32.wglGetCurrentContext()) temporaryContext.reset(new QOpenGLTemporaryContext); - QOpenGLStaticContext *result = new QOpenGLStaticContext; + auto *result = new QOpenGLStaticContext; qCDebug(lcQpaGl) << __FUNCTION__ << *result; return result; } @@ -1051,7 +1051,7 @@ QWindowsGLContext::QWindowsGLContext(QOpenGLStaticContext *staticContext, qWarning("QWindowsGLContext: Requires a QWGLNativeContext"); return; } - QWGLNativeContext handle = nativeHandle.value<QWGLNativeContext>(); + auto handle = nativeHandle.value<QWGLNativeContext>(); HGLRC wglcontext = handle.context(); HWND wnd = handle.window(); if (!wglcontext || !wnd) { @@ -1233,7 +1233,7 @@ bool QWindowsGLContext::updateObtainedParams(HDC hdc, int *obtainedSwapInterval) hasRobustness = exts && strstr(exts, "GL_ARB_robustness"); } else { typedef const GLubyte * (APIENTRY *glGetStringi_t)(GLenum, GLuint); - glGetStringi_t glGetStringi = reinterpret_cast<glGetStringi_t>( + auto glGetStringi = reinterpret_cast<glGetStringi_t>( reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress("glGetStringi"))); if (glGetStringi) { GLint n = 0; @@ -1305,7 +1305,7 @@ bool QWindowsGLContext::makeCurrent(QPlatformSurface *surface) Q_ASSERT(surface->surface()->supportsOpenGL()); // Do we already have a DC entry for that window? - QWindowsWindow *window = static_cast<QWindowsWindow *>(surface); + auto *window = static_cast<QWindowsWindow *>(surface); window->aboutToMakeCurrent(); const HWND hwnd = window->handle(); if (const QOpenGLContextData *contextData = findByHWND(m_windowContexts, hwnd)) { @@ -1374,7 +1374,7 @@ QFunctionPointer QWindowsGLContext::getProcAddress(const char *procName) // Even though we use QFunctionPointer, it does not mean the function can be called. // It will need to be cast to the proper function type with the correct calling // convention. QFunctionPointer is nothing more than a glorified void* here. - QFunctionPointer procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); + auto procAddress = reinterpret_cast<QFunctionPointer>(QOpenGLStaticContext::opengl32.wglGetProcAddress(procName)); // We support AllGLFunctionsQueryable, which means this function must be able to // return a function pointer even for functions that are in GL.h and exported diff --git a/src/plugins/platforms/windows/qwindowsinputcontext.cpp b/src/plugins/platforms/windows/qwindowsinputcontext.cpp index 71ed33f85b..e681dbb0cb 100644 --- a/src/plugins/platforms/windows/qwindowsinputcontext.cpp +++ b/src/plugins/platforms/windows/qwindowsinputcontext.cpp @@ -717,7 +717,7 @@ int QWindowsInputContext::reconvertString(RECONVERTSTRING *reconv) reconv->dwCompStrOffset = DWORD(startPos) * sizeof(ushort); // byte count. reconv->dwTargetStrLen = reconv->dwCompStrLen; reconv->dwTargetStrOffset = reconv->dwCompStrOffset; - ushort *pastReconv = reinterpret_cast<ushort *>(reconv + 1); + auto *pastReconv = reinterpret_cast<ushort *>(reconv + 1); std::copy(surroundingText.utf16(), surroundingText.utf16() + surroundingText.size(), QT_MAKE_UNCHECKED_ARRAY_ITERATOR(pastReconv)); return memSize; diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index f0754e3e57..eccf1c4928 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -324,7 +324,7 @@ bool QWindowsIntegration::hasCapability(QPlatformIntegration::Capability cap) co QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) const { if (window->type() == Qt::Desktop) { - QWindowsDesktopWindow *result = new QWindowsDesktopWindow(window); + auto *result = new QWindowsDesktopWindow(window); qCDebug(lcQpaWindows) << "Desktop window:" << window << Qt::showbase << Qt::hex << result->winId() << Qt::noshowbase << Qt::dec << result->geometry(); return result; @@ -371,7 +371,7 @@ QPlatformWindow *QWindowsIntegration::createForeignWindow(QWindow *window, WId n qWarning("Windows QPA: Invalid foreign window ID %p.", hwnd); return nullptr; } - QWindowsForeignWindow *result = new QWindowsForeignWindow(window, hwnd); + auto *result = new QWindowsForeignWindow(window, hwnd); const QRect obtainedGeometry = result->geometry(); QScreen *screen = nullptr; if (const QPlatformScreen *pScreen = result->screenForGeometry(obtainedGeometry)) diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp index 44668cde78..4b54051e0c 100644 --- a/src/plugins/platforms/windows/qwindowskeymapper.cpp +++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp @@ -100,7 +100,7 @@ QWindowsKeyMapper::QWindowsKeyMapper() : m_useRTLExtensions(false), m_keyGrabber(nullptr) { memset(keyLayout, 0, sizeof(keyLayout)); - QGuiApplication *app = static_cast<QGuiApplication *>(QGuiApplication::instance()); + auto *app = static_cast<QGuiApplication *>(QGuiApplication::instance()); QObject::connect(app, &QGuiApplication::applicationStateChanged, app, clearKeyRecorderOnApplicationInActive); changeKeyboard(); @@ -950,7 +950,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, const UINT msgType = msg.message; const quint32 scancode = (msg.lParam >> 16) & scancodeBitmask; - quint32 vk_key = quint32(msg.wParam); + auto vk_key = quint32(msg.wParam); quint32 nModifiers = 0; QWindow *receiver = m_keyGrabber ? m_keyGrabber : window; @@ -1182,7 +1182,7 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, MSG msg, // results, if we map this virtual key-code directly (for eg '?' US layouts). So try // to find the correct key using the current message parameters & keyboard state. if (uch.isNull() && msgType == WM_IME_KEYDOWN) { - const QWindowsInputContext *windowsInputContext = + const auto *windowsInputContext = qobject_cast<const QWindowsInputContext *>(QWindowsIntegration::instance()->inputContext()); if (!(windowsInputContext && windowsInputContext->isComposing())) vk_key = ImmGetVirtualKey(reinterpret_cast<HWND>(window->winId())); diff --git a/src/plugins/platforms/windows/qwindowsmenu.cpp b/src/plugins/platforms/windows/qwindowsmenu.cpp index e55e283fe1..d20edd685e 100644 --- a/src/plugins/platforms/windows/qwindowsmenu.cpp +++ b/src/plugins/platforms/windows/qwindowsmenu.cpp @@ -518,7 +518,7 @@ QWindowsMenu::~QWindowsMenu() void QWindowsMenu::insertMenuItem(QPlatformMenuItem *menuItemIn, QPlatformMenuItem *before) { qCDebug(lcQpaMenus) << __FUNCTION__ << '(' << menuItemIn << ", before=" << before << ')' << this; - QWindowsMenuItem *menuItem = static_cast<QWindowsMenuItem *>(menuItemIn); + auto *menuItem = static_cast<QWindowsMenuItem *>(menuItemIn); const int index = insertBefore(&m_menuItems, menuItemIn, before); const bool append = index == m_menuItems.size() - 1; menuItem->insertIntoMenu(this, append, index); @@ -689,7 +689,7 @@ void QWindowsPopupMenu::showPopup(const QWindow *parentWindow, const QRect &targ const QPlatformMenuItem *item) { qCDebug(lcQpaMenus) << __FUNCTION__ << '>' << this << parentWindow << targetRect << item; - const QWindowsBaseWindow *window = static_cast<const QWindowsBaseWindow *>(parentWindow->handle()); + const auto *window = static_cast<const QWindowsBaseWindow *>(parentWindow->handle()); const QPoint globalPos = window->mapToGlobal(targetRect.topLeft()); trackPopupMenu(window->handle(), globalPos.x(), globalPos.y()); } @@ -756,7 +756,7 @@ QWindowsMenuBar::~QWindowsMenuBar() void QWindowsMenuBar::insertMenu(QPlatformMenu *menuIn, QPlatformMenu *before) { qCDebug(lcQpaMenus) << __FUNCTION__ << menuIn << "before=" << before; - QWindowsMenu *menu = static_cast<QWindowsMenu *>(menuIn); + auto *menu = static_cast<QWindowsMenu *>(menuIn); const int index = insertBefore(&m_menus, menuIn, before); menu->insertIntoMenuBar(this, index == m_menus.size() - 1, index); } diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp index 030d8d1e0f..b9d8b191f5 100644 --- a/src/plugins/platforms/windows/qwindowsmime.cpp +++ b/src/plugins/platforms/windows/qwindowsmime.cpp @@ -178,7 +178,7 @@ static bool qt_write_dibv5(QDataStream &s, QImage image) if (image.format() != QImage::Format_ARGB32) image = image.convertToFormat(QImage::Format_ARGB32); - uchar *buf = new uchar[bpl_bmp]; + auto *buf = new uchar[bpl_bmp]; memset(buf, 0, size_t(bpl_bmp)); for (int y=image.height()-1; y>=0; y--) { @@ -264,7 +264,7 @@ static bool qt_read_dibv5(QDataStream &s, QImage &image) const int bpl = image.bytesPerLine(); uchar *data = image.bits(); - uchar *buf24 = new uchar[bpl]; + auto *buf24 = new uchar[bpl]; const int bpl24 = ((w * nbits + 31) / 32) * 4; while (--h >= 0) { @@ -286,7 +286,7 @@ static bool qt_read_dibv5(QDataStream &s, QImage &image) if (bi.bV5Height < 0) { // Flip the image - uchar *buf = new uchar[bpl]; + auto *buf = new uchar[bpl]; h = -bi.bV5Height; for (int y = 0; y < h/2; ++y) { memcpy(buf, data + y * bpl, size_t(bpl)); @@ -772,16 +772,16 @@ bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeDat } QByteArray result(size, '\0'); - DROPFILES* d = reinterpret_cast<DROPFILES *>(result.data()); + auto* d = reinterpret_cast<DROPFILES *>(result.data()); d->pFiles = sizeof(DROPFILES); GetCursorPos(&d->pt); // try d->fNC = true; char *files = (reinterpret_cast<char*>(d)) + d->pFiles; d->fWide = true; - wchar_t *f = reinterpret_cast<wchar_t *>(files); + auto *f = reinterpret_cast<wchar_t *>(files); for (int i=0; i<fileNames.size(); i++) { - const size_t l = size_t(fileNames.at(i).length()); + const auto l = size_t(fileNames.at(i).length()); memcpy(f, fileNames.at(i).utf16(), l * sizeof(ushort)); f += l; *f++ = 0; @@ -852,9 +852,9 @@ QVariant QWindowsMimeURI::convertToMime(const QString &mimeType, LPDATAOBJECT pD if (data.isEmpty()) return QVariant(); - const DROPFILES *hdrop = reinterpret_cast<const DROPFILES *>(data.constData()); + const auto *hdrop = reinterpret_cast<const DROPFILES *>(data.constData()); if (hdrop->fWide) { - const wchar_t *filesw = reinterpret_cast<const wchar_t *>(data.constData() + hdrop->pFiles); + const auto *filesw = reinterpret_cast<const wchar_t *>(data.constData() + hdrop->pFiles); int i = 0; while (filesw[i]) { QString fileurl = QString::fromWCharArray(filesw + i); @@ -1055,7 +1055,7 @@ QVector<FORMATETC> QWindowsMimeImage::formatsForMime(const QString &mimeType, co QVector<FORMATETC> formatetcs; if (mimeData->hasImage() && mimeType == QLatin1String("application/x-qt-image")) { //add DIBV5 if image has alpha channel. Do not add CF_PNG here as it will confuse MS Office (QTBUG47656). - QImage image = qvariant_cast<QImage>(mimeData->imageData()); + auto image = qvariant_cast<QImage>(mimeData->imageData()); if (!image.isNull() && image.hasAlphaChannel()) formatetcs += setCf(CF_DIBV5); formatetcs += setCf(CF_DIB); @@ -1097,7 +1097,7 @@ bool QWindowsMimeImage::convertFromMime(const FORMATETC &formatetc, const QMimeD { int cf = getCf(formatetc); if ((cf == CF_DIB || cf == CF_DIBV5 || cf == int(CF_PNG)) && mimeData->hasImage()) { - QImage img = qvariant_cast<QImage>(mimeData->imageData()); + auto img = qvariant_cast<QImage>(mimeData->imageData()); if (img.isNull()) return false; QByteArray ba; diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index c15819a65f..6df5e6aa27 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -127,7 +127,7 @@ static inline QTouchDevice *createTouchDevice() qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY) << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints; - QTouchDevice *result = new QTouchDevice; + auto *result = new QTouchDevice; result->setType(digitizers & NID_INTEGRATED_TOUCH ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad); QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition; @@ -306,7 +306,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // However, when tablet support is active, extraInfo is a packet serial number. This is not a problem // since we do not want to ignore mouse events coming from a tablet. // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms703320.aspx - const quint64 extraInfo = quint64(GetMessageExtraInfo()); + const auto extraInfo = quint64(GetMessageExtraInfo()); if ((extraInfo & signatureMask) == miWpSignature) { if (extraInfo & 0x80) { // Bit 7 indicates touch event, else tablet pen. source = Qt::MouseEventSynthesizedBySystem; @@ -370,7 +370,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, return true; } - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); // If the window was recently resized via mouse doubleclick on the frame or title bar, // we don't get WM_LBUTTONDOWN or WM_LBUTTONDBLCLK for the second click, diff --git a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp index e581b30ced..d1d181d66e 100644 --- a/src/plugins/platforms/windows/qwindowsnativeinterface.cpp +++ b/src/plugins/platforms/windows/qwindowsnativeinterface.cpp @@ -98,7 +98,7 @@ void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resourc qWarning("%s: '%s' requested for null window or window without handle.", __FUNCTION__, resource.constData()); return nullptr; } - QWindowsWindow *bw = static_cast<QWindowsWindow *>(window->handle()); + auto *bw = static_cast<QWindowsWindow *>(window->handle()); int type = resourceType(resource); if (type == HandleType) return bw->handle(); @@ -131,7 +131,7 @@ void *QWindowsNativeInterface::nativeResourceForScreen(const QByteArray &resourc qWarning("%s: '%s' requested for null screen or screen without handle.", __FUNCTION__, resource.constData()); return nullptr; } - QWindowsScreen *bs = static_cast<QWindowsScreen *>(screen->handle()); + auto *bs = static_cast<QWindowsScreen *>(screen->handle()); int type = resourceType(resource); if (type == HandleType) return bs->handle(); @@ -157,7 +157,7 @@ static const char customMarginPropertyC[] = "WindowsCustomMargins"; QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + auto *platformWindow = static_cast<QWindowsWindow *>(window); if (name == QLatin1String(customMarginPropertyC)) return QVariant::fromValue(platformWindow->customMargins()); return QVariant(); @@ -171,7 +171,7 @@ QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window); + auto *platformWindow = static_cast<QWindowsWindow *>(window); if (name == QLatin1String(customMarginPropertyC)) platformWindow->setCustomMargins(qvariant_cast<QMargins>(value)); } @@ -206,7 +206,7 @@ void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resour return nullptr; } - QWindowsOpenGLContext *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); + auto *glcontext = static_cast<QWindowsOpenGLContext *>(context->handle()); switch (resourceType(resource)) { case RenderingContextType: // Fall through. case EglContextType: diff --git a/src/plugins/platforms/windows/qwindowsole.cpp b/src/plugins/platforms/windows/qwindowsole.cpp index fb6a74581a..f3450e2806 100644 --- a/src/plugins/platforms/windows/qwindowsole.cpp +++ b/src/plugins/platforms/windows/qwindowsole.cpp @@ -155,7 +155,7 @@ QWindowsOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL HRESULT hr = ResultFromScode(E_NOTIMPL); if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) { - DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal); + auto * val = (DWORD*)GlobalLock(pMedium->hGlobal); performedEffect = *val; GlobalUnlock(pMedium->hGlobal); if (fRelease) @@ -193,7 +193,7 @@ QWindowsOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppe fmtetcs.append(formatetc); } - QWindowsOleEnumFmtEtc *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs); + auto *enumFmtEtc = new QWindowsOleEnumFmtEtc(fmtetcs); *ppenumFormatEtc = enumFmtEtc; if (enumFmtEtc->isNull()) { delete enumFmtEtc; @@ -237,7 +237,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<FORMATETC> &fmtetcs) qCDebug(lcQpaMime) << __FUNCTION__ << fmtetcs; m_lpfmtetcs.reserve(fmtetcs.count()); for (int idx = 0; idx < fmtetcs.count(); ++idx) { - LPFORMATETC destetc = new FORMATETC(); + auto destetc = new FORMATETC(); if (copyFormatEtc(destetc, &(fmtetcs.at(idx)))) { m_lpfmtetcs.append(destetc); } else { @@ -255,7 +255,7 @@ QWindowsOleEnumFmtEtc::QWindowsOleEnumFmtEtc(const QVector<LPFORMATETC> &lpfmtet m_lpfmtetcs.reserve(lpfmtetcs.count()); for (int idx = 0; idx < lpfmtetcs.count(); ++idx) { LPFORMATETC srcetc = lpfmtetcs.at(idx); - LPFORMATETC destetc = new FORMATETC(); + auto destetc = new FORMATETC(); if (copyFormatEtc(destetc, srcetc)) { m_lpfmtetcs.append(destetc); } else { @@ -357,7 +357,7 @@ QWindowsOleEnumFmtEtc::Clone(LPENUMFORMATETC FAR* newEnum) if (newEnum == nullptr) return ResultFromScode(E_INVALIDARG); - QWindowsOleEnumFmtEtc *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); + auto *result = new QWindowsOleEnumFmtEtc(m_lpfmtetcs); result->m_nIndex = m_nIndex; if (result->isNull()) { diff --git a/src/plugins/platforms/windows/qwindowsopengltester.cpp b/src/plugins/platforms/windows/qwindowsopengltester.cpp index ff495c8290..afc1991e2c 100644 --- a/src/plugins/platforms/windows/qwindowsopengltester.cpp +++ b/src/plugins/platforms/windows/qwindowsopengltester.cpp @@ -457,7 +457,7 @@ bool QWindowsOpenGLTester::testDesktopGL() // Check the version. If we got 1.x then it's all hopeless and we can stop right here. typedef const GLubyte * (APIENTRY * GetString_t)(GLenum name); - GetString_t GetString = reinterpret_cast<GetString_t>( + auto GetString = reinterpret_cast<GetString_t>( reinterpret_cast<QFunctionPointer>(::GetProcAddress(lib, "glGetString"))); if (GetString) { if (const char *versionStr = reinterpret_cast<const char *>(GetString(GL_VERSION))) { diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 36c614af34..b3d961db72 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -269,7 +269,10 @@ static Qt::MouseButtons queryMouseButtons() static QWindow *getWindowUnderPointer(QWindow *window, QPoint globalPos) { - QWindow *currentWindowUnderPointer = QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT); + QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + + QWindow *currentWindowUnderPointer = platformWindow->hasMouseCapture() ? + QWindowsScreen::windowAt(globalPos, CWP_SKIPINVISIBLE | CWP_SKIPTRANSPARENT) : window; while (currentWindowUnderPointer && currentWindowUnderPointer->flags() & Qt::WindowTransparentForInput) currentWindowUnderPointer = currentWindowUnderPointer->parent(); @@ -318,7 +321,7 @@ static QTouchDevice *createTouchDevice() qCDebug(lcQpaEvents) << "Digitizers:" << Qt::hex << Qt::showbase << (digitizers & ~NID_READY) << "Ready:" << (digitizers & NID_READY) << Qt::dec << Qt::noshowbase << "Tablet PC:" << tabletPc << "Max touch points:" << maxTouchPoints; - QTouchDevice *result = new QTouchDevice; + auto *result = new QTouchDevice; result->setType(digitizers & NID_INTEGRATED_TOUCH ? QTouchDevice::TouchScreen : QTouchDevice::TouchPad); QTouchDevice::Capabilities capabilities = QTouchDevice::Position | QTouchDevice::Area | QTouchDevice::NormalizedPosition; @@ -348,7 +351,7 @@ void QWindowsPointerHandler::handleCaptureRelease(QWindow *window, QEvent::Type eventType, Qt::MouseButtons mouseButtons) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); // Qt expects the platform plugin to capture the mouse on any button press until release. if (!platformWindow->hasMouseCapture() && eventType == QEvent::MouseButtonPress) { @@ -384,7 +387,7 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos) { - QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); + auto *platformWindow = static_cast<QWindowsWindow *>(window->handle()); const bool hasCapture = platformWindow->hasMouseCapture(); // No enter or leave events are sent as long as there is an autocapturing window. @@ -468,7 +471,7 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (!screen) return false; - POINTER_TOUCH_INFO *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); + auto *touchInfo = static_cast<POINTER_TOUCH_INFO *>(vTouchInfo); const QRect screenGeometry = screen->geometry(); @@ -548,13 +551,13 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin if (et & QtWindows::NonClientEventFlag) return false; // Let DefWindowProc() handle Non Client messages. - POINTER_PEN_INFO *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo); + auto *penInfo = static_cast<POINTER_PEN_INFO *>(vPenInfo); RECT pRect, dRect; if (!QWindowsContext::user32dll.getPointerDeviceRects(penInfo->pointerInfo.sourceDevice, &pRect, &dRect)) return false; - const qint64 sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice; + const auto sourceDevice = (qint64)penInfo->pointerInfo.sourceDevice; const QPoint globalPos = QPoint(penInfo->pointerInfo.ptPixelLocation.x, penInfo->pointerInfo.ptPixelLocation.y); const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos); const QPointF hiResGlobalPos = QPointF(dRect.left + qreal(penInfo->pointerInfo.ptHimetricLocation.x - pRect.left) diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp index e3931b3bb1..d919d97211 100644 --- a/src/plugins/platforms/windows/qwindowsscreen.cpp +++ b/src/plugins/platforms/windows/qwindowsscreen.cpp @@ -91,7 +91,7 @@ static bool monitorData(HMONITOR hMonitor, QWindowsScreenData *data) } else { if (const HDC hdc = CreateDC(info.szDevice, nullptr, nullptr, nullptr)) { const QDpi dpi = monitorDPI(hMonitor); - data->dpi = dpi.first ? dpi : deviceDPI(hdc); + data->dpi = dpi.first > 0 ? dpi : deviceDPI(hdc); data->depth = GetDeviceCaps(hdc, BITSPIXEL); data->format = data->depth == 16 ? QImage::Format_RGB16 : QImage::Format_RGB32; data->physicalSizeMM = QSizeF(GetDeviceCaps(hdc, HORZSIZE), GetDeviceCaps(hdc, VERTSIZE)); @@ -120,7 +120,7 @@ BOOL QT_WIN_CALLBACK monitorEnumCallback(HMONITOR hMonitor, HDC, LPRECT, LPARAM { QWindowsScreenData data; if (monitorData(hMonitor, &data)) { - WindowsScreenDataList *result = reinterpret_cast<WindowsScreenDataList *>(p); + auto *result = reinterpret_cast<WindowsScreenDataList *>(p); // QWindowSystemInterface::handleScreenAdded() documentation specifies that first // added screen will be the primary screen, so order accordingly. // Note that the side effect of this policy is that there is no way to change primary @@ -552,7 +552,7 @@ bool QWindowsScreenManager::handleScreenChanges() if (existingIndex != -1) { m_screens.at(existingIndex)->handleChanges(newData); } else { - QWindowsScreen *newScreen = new QWindowsScreen(newData); + auto *newScreen = new QWindowsScreen(newData); m_screens.push_back(newScreen); QWindowSystemInterface::handleScreenAdded(newScreen, newData.flags & QWindowsScreenData::PrimaryScreen); diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp index 9504513a5e..b2b1dee232 100644 --- a/src/plugins/platforms/windows/qwindowsservices.cpp +++ b/src/plugins/platforms/windows/qwindowsservices.cpp @@ -57,7 +57,7 @@ static inline bool shellExecute(const QUrl &url) const QString nativeFilePath = url.isLocalFile() && !url.hasFragment() && !url.hasQuery() ? QDir::toNativeSeparators(url.toLocalFile()) : url.toString(QUrl::FullyEncoded); - const quintptr result = + const auto result = reinterpret_cast<quintptr>(ShellExecute(nullptr, nullptr, reinterpret_cast<const wchar_t *>(nativeFilePath.utf16()), nullptr, nullptr, SW_SHOWNORMAL)); diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index b75c64c40e..437c9562ab 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -162,8 +162,8 @@ public: m_init = CoInitializeEx(nullptr, COINIT_MULTITHREADED); QMutexLocker readyLocker(&m_readyMutex); - while (!m_cancelled.load()) { - if (!m_params && !m_cancelled.load() + while (!m_cancelled.loadRelaxed()) { + if (!m_params && !m_cancelled.loadRelaxed() && !m_readyCondition.wait(&m_readyMutex, 1000)) continue; @@ -174,7 +174,7 @@ public: m_params->attributes, &info, sizeof(SHFILEINFO), m_params->flags); m_doneMutex.lock(); - if (!m_cancelled.load()) { + if (!m_cancelled.loadRelaxed()) { *m_params->result = result; memcpy(m_params->info, &info, sizeof(SHFILEINFO)); } @@ -204,7 +204,7 @@ public: void cancel() { QMutexLocker doneLocker(&m_doneMutex); - m_cancelled.store(1); + m_cancelled.storeRelaxed(1); m_readyCondition.wakeAll(); } @@ -583,7 +583,7 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon); static QPixmap loadIconFromShell32(int resourceId, QSizeF size) { if (const HMODULE hmod = QSystemLibrary::load(L"shell32")) { - HICON iconHandle = + auto iconHandle = static_cast<HICON>(LoadImage(hmod, MAKEINTRESOURCE(resourceId), IMAGE_ICON, int(size.width()), int(size.height()), 0)); if (iconHandle) { diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp index b52a82c9f1..e80eefc34d 100644 --- a/src/plugins/platforms/windows/qwindowswindow.cpp +++ b/src/plugins/platforms/windows/qwindowswindow.cpp @@ -764,8 +764,8 @@ QWindowsWindowData if (title.isEmpty() && (result.flags & Qt::WindowTitleHint)) title = topLevel ? qAppName() : w->objectName(); - const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); - const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); + const auto *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16()); + const auto *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16()); // Capture events before CreateWindowEx() returns. The context is cleared in // the QWindowsWindow constructor. @@ -883,10 +883,12 @@ static QSize toNativeSizeConstrained(QSize dip, const QWindow *w) { if (QHighDpiScaling::isActive()) { const qreal factor = QHighDpiScaling::factor(w); - if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) - dip.rwidth() *= factor; - if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) - dip.rheight() *= factor; + if (!qFuzzyCompare(factor, qreal(1))) { + if (dip.width() > 0 && dip.width() < QWINDOWSIZE_MAX) + dip.setWidth(qRound(qreal(dip.width()) * factor)); + if (dip.height() > 0 && dip.height() < QWINDOWSIZE_MAX) + dip.setHeight(qRound(qreal(dip.height()) * factor)); + } } return dip; } @@ -980,7 +982,7 @@ bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, co if (!msg.wParam || customMargins.isNull()) return false; *result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam); - NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); + auto *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam); const RECT oldClientArea = ncp->rgrc[0]; ncp->rgrc[0].left += customMargins.left(); ncp->rgrc[0].top += customMargins.top(); @@ -1500,7 +1502,7 @@ QWindow *QWindowsWindow::topLevelOf(QWindow *w) w = parent; if (const QPlatformWindow *handle = w->handle()) { - const QWindowsWindow *ww = static_cast<const QWindowsWindow *>(handle); + const auto *ww = static_cast<const QWindowsWindow *>(handle); if (ww->isEmbedded()) { HWND parentHWND = GetAncestor(ww->handle(), GA_PARENT); const HWND desktopHwnd = GetDesktopWindow(); @@ -1574,7 +1576,7 @@ bool QWindowsWindow::isActive() const bool QWindowsWindow::isAncestorOf(const QPlatformWindow *child) const { - const QWindowsWindow *childWindow = static_cast<const QWindowsWindow *>(child); + const auto *childWindow = static_cast<const QWindowsWindow *>(child); return IsChild(m_data.hwnd, childWindow->handle()); } @@ -1723,7 +1725,7 @@ void QWindowsWindow::setParent_sys(const QPlatformWindow *parent) HWND oldParentHWND = parentHwnd(); HWND newParentHWND = nullptr; if (parent) { - const QWindowsWindow *parentW = static_cast<const QWindowsWindow *>(parent); + const auto *parentW = static_cast<const QWindowsWindow *>(parent); newParentHWND = parentW->handle(); } @@ -2366,7 +2368,7 @@ void QWindowsWindow::propagateSizeHints() bool QWindowsWindow::handleGeometryChangingMessage(MSG *message, const QWindow *qWindow, const QMargins &margins) { - WINDOWPOS *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); + auto *windowPos = reinterpret_cast<WINDOWPOS *>(message->lParam); if ((windowPos->flags & SWP_NOZORDER) == 0) { if (QWindowsWindow *platformWindow = QWindowsWindow::windowsWindowOf(qWindow)) { QWindow *parentWindow = qWindow->parent(); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index a427e553f0..943c1ff368 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -82,7 +82,7 @@ QWindowsUiaMainProvider *QWindowsUiaMainProvider::providerForAccessible(QAccessi QAccessible::Id id = QAccessible::uniqueId(accessible); QWindowsUiaProviderCache *providerCache = QWindowsUiaProviderCache::instance(); - QWindowsUiaMainProvider *provider = qobject_cast<QWindowsUiaMainProvider *>(providerCache->providerForId(id)); + auto *provider = qobject_cast<QWindowsUiaMainProvider *>(providerCache->providerForId(id)); if (provider) { provider->AddRef(); @@ -153,7 +153,7 @@ void QWindowsUiaMainProvider::notifyValueChange(QAccessibleValueChangeEvent *eve int count = listacc->childCount(); for (int i = 0; i < count; ++i) { QAccessibleInterface *item = listacc->child(i); - if (item && item->text(QAccessible::Name) == event->value()) { + if (item && item->isValid() && item->text(QAccessible::Name) == event->value()) { if (!item->state().selected) { if (QAccessibleActionInterface *actionInterface = item->actionInterface()) actionInterface->doAction(QAccessibleActionInterface::toggleAction()); diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp index 9d1e72fb78..50ecfc7ecd 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextprovider.cpp @@ -100,7 +100,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRet for (LONG i = 0; i < selCount; ++i) { int startOffset = 0, endOffset = 0; textInterface->selection((int)i, &startOffset, &endOffset); - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), startOffset, endOffset); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), startOffset, endOffset); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } @@ -110,7 +110,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetSelection(SAFEARRAY **pRet if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { LONG i = 0; int cursorPosition = textInterface->cursorPosition(); - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), cursorPosition, cursorPosition); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } @@ -138,7 +138,7 @@ HRESULT STDMETHODCALLTYPE QWindowsUiaTextProvider::GetVisibleRanges(SAFEARRAY ** // Considering the entire text as visible. if ((*pRetVal = SafeArrayCreateVector(VT_UNKNOWN, 0, 1))) { LONG i = 0; - QWindowsUiaTextRangeProvider *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); + auto *textRangeProvider = new QWindowsUiaTextRangeProvider(id(), 0, textInterface->characterCount()); SafeArrayPutElement(*pRetVal, &i, static_cast<IUnknown *>(textRangeProvider)); textRangeProvider->Release(); } diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp index 1be186f6b3..8e395669f8 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiatextrangeprovider.cpp @@ -92,7 +92,7 @@ HRESULT QWindowsUiaTextRangeProvider::Compare(ITextRangeProvider *range, BOOL *p if (!range || !pRetVal) return E_INVALIDARG; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(range); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(range); *pRetVal = ((targetProvider->m_startOffset == m_startOffset) && (targetProvider->m_endOffset == m_endOffset)); return S_OK; } @@ -110,7 +110,7 @@ HRESULT QWindowsUiaTextRangeProvider::CompareEndpoints(TextPatternRangeEndpoint if (!targetRange || !pRetVal) return E_INVALIDARG; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); int point = (endpoint == TextPatternRangeEndpoint_Start) ? m_startOffset : m_endOffset; int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? @@ -373,7 +373,7 @@ HRESULT QWindowsUiaTextRangeProvider::MoveEndpointByRange(TextPatternRangeEndpoi qCDebug(lcQpaUiAutomation) << __FUNCTION__ << "endpoint=" << endpoint << "targetRange=" << targetRange << "targetEndpoint=" << targetEndpoint << "this: " << this; - QWindowsUiaTextRangeProvider *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); + auto *targetProvider = static_cast<QWindowsUiaTextRangeProvider *>(targetRange); int targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start) ? targetProvider->m_startOffset : targetProvider->m_endOffset; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp index 7980826b49..ab04384616 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiautils.cpp @@ -114,7 +114,7 @@ void setVariantBool(bool value, VARIANT *variant) void setVariantDouble(double value, VARIANT *variant) { variant->vt = VT_R8; - variant->boolVal = value; + variant->dblVal = value; } BSTR bStrFromQString(const QString &value) diff --git a/src/plugins/platforms/winrt/qwinrtscreen.cpp b/src/plugins/platforms/winrt/qwinrtscreen.cpp index e611c7be24..0d77889a36 100644 --- a/src/plugins/platforms/winrt/qwinrtscreen.cpp +++ b/src/plugins/platforms/winrt/qwinrtscreen.cpp @@ -1097,7 +1097,7 @@ HRESULT QWinRTScreen::onPointerEntered(ICoreWindow *, IPointerEventArgs *args) d->currentTargetWindow = topWindow(); if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); qCDebug(lcQpaEvents) << __FUNCTION__ << "handleEnterEvent" << d->currentTargetWindow << pos; QWindowSystemInterface::handleEnterEvent(d->currentTargetWindow, pos, pos); @@ -1121,7 +1121,7 @@ HRESULT QWinRTScreen::onPointerExited(ICoreWindow *, IPointerEventArgs *args) d->touchPoints.remove(id); if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); qCDebug(lcQpaEvents) << __FUNCTION__ << "handleLeaveEvent" << d->currentTargetWindow; QWindowSystemInterface::handleLeaveEvent(d->currentTargetWindow); @@ -1152,7 +1152,7 @@ HRESULT QWinRTScreen::onPointerUpdated(ICoreWindow *, IPointerEventArgs *args) d->currentTargetWindow = windowUnderPointer; if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); if (d->currentTargetWindow) { const QPointF globalPosDelta = pos - posPoint; @@ -1354,7 +1354,7 @@ void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransitio d->currentTargetWindow = windowUnderPointer; if (d->mouseGrabWindow) - d->currentTargetWindow = d->mouseGrabWindow.load()->window(); + d->currentTargetWindow = d->mouseGrabWindow.loadRelaxed()->window(); if (d->currentTargetWindow) { const QPointF globalPosDelta = pos - posPoint; diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp index 4adf662152..f26f698e76 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp @@ -204,7 +204,6 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat , m_shareContext(0) , m_format(format) , m_isPBufferCurrent(false) - , m_swapInterval(-1) , m_ownsContext(nativeHandle.isNull()) , m_getGraphicsResetStatus(0) , m_lost(false) @@ -567,9 +566,9 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface) if (success && surfaceClass == QSurface::Window) { int interval = surface->format().swapInterval(); + QXcbWindow *window = static_cast<QXcbWindow *>(surface); QXcbScreen *screen = screenForPlatformSurface(surface); - if (interval >= 0 && m_swapInterval != interval && screen) { - m_swapInterval = interval; + if (interval >= 0 && interval != window->swapInterval() && screen) { typedef void (*qt_glXSwapIntervalEXT)(Display *, GLXDrawable, int); typedef void (*qt_glXSwapIntervalMESA)(unsigned int); static qt_glXSwapIntervalEXT glXSwapIntervalEXT = 0; @@ -588,6 +587,7 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface) glXSwapIntervalEXT(m_display, glxDrawable, interval); else if (glXSwapIntervalMESA) glXSwapIntervalMESA(interval); + window->setSwapInterval(interval); } } diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h index be9d3f5dcb..2a88fd6e59 100644 --- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h +++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.h @@ -87,7 +87,6 @@ private: GLXContext m_shareContext; QSurfaceFormat m_format; bool m_isPBufferCurrent; - int m_swapInterval; bool m_ownsContext; GLenum (APIENTRY * m_getGraphicsResetStatus)(); bool m_lost; diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp index bfc105a040..8c34bd9c91 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.cpp +++ b/src/plugins/platforms/xcb/qxcbscreen.cpp @@ -658,16 +658,24 @@ QImage::Format QXcbScreen::format() const return format; } -QDpi QXcbScreen::logicalDpi() const +int QXcbScreen::forcedDpi() const { static const int overrideDpi = qEnvironmentVariableIntValue("QT_FONT_DPI"); if (overrideDpi) - return QDpi(overrideDpi, overrideDpi); + return overrideDpi; const int forcedDpi = m_virtualDesktop->forcedDpi(); - if (forcedDpi > 0) { + if (forcedDpi > 0) + return forcedDpi; + return 0; +} + +QDpi QXcbScreen::logicalDpi() const +{ + const int forcedDpi = this->forcedDpi(); + if (forcedDpi > 0) return QDpi(forcedDpi, forcedDpi); - } + return m_virtualDesktop->dpi(); } @@ -739,7 +747,9 @@ void QXcbScreen::updateGeometry(const QRect &geometry, uint8_t rotation) if (m_sizeMillimeters.isEmpty()) m_sizeMillimeters = sizeInMillimeters(geometry.size(), m_virtualDesktop->dpi()); - qreal dpi = geometry.width() / physicalSize().width() * qreal(25.4); + qreal dpi = forcedDpi(); + if (dpi <= 0) + dpi = geometry.width() / physicalSize().width() * qreal(25.4); // Use 128 as a reference DPI on small screens. This favors "small UI" over "large UI". qreal referenceDpi = physicalSize().width() <= 320 ? 128 : 96; diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h index be6c45e415..ec3b07bfb7 100644 --- a/src/plugins/platforms/xcb/qxcbscreen.h +++ b/src/plugins/platforms/xcb/qxcbscreen.h @@ -208,6 +208,7 @@ public: private: void sendStartupMessage(const QByteArray &message) const; + int forcedDpi() const; QByteArray getOutputProperty(xcb_atom_t atom) const; QByteArray getEdid() const; diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index e4a04f5308..5de5974ca7 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -184,6 +184,9 @@ public: static void setWindowTitle(const QXcbConnection *conn, xcb_window_t window, const QString &title); static QString windowTitle(const QXcbConnection *conn, xcb_window_t window); + int swapInterval() const { return m_swapInterval; } + void setSwapInterval(int swapInterval) { m_swapInterval = swapInterval; } + public Q_SLOTS: void updateSyncRequestCounter(); @@ -276,6 +279,7 @@ protected: SyncState m_syncState = NoSyncNeeded; QXcbSyncWindowRequest *m_pendingSyncRequest = nullptr; + int m_swapInterval = -1; }; class QXcbForeignWindow : public QXcbWindow |