diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-05-27 09:16:56 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2019-05-27 09:17:14 +0200 |
commit | 65cfac73bd1c09eafadf57a3b7161f52b186c37d (patch) | |
tree | cb5c4f4fdc47ba9a54f22a996a6bff8b412a2c10 /src | |
parent | 9fc17c14fa682984742e8febd7551dd18bc36726 (diff) | |
parent | 761b71bd20524bc1e495508a52c38a0bc6679a06 (diff) |
Merge "Merge remote-tracking branch 'origin/5.12' into 5.13"
Diffstat (limited to 'src')
34 files changed, 949 insertions, 237 deletions
diff --git a/src/corelib/doc/snippets/cmake-macros/examples.cmake b/src/corelib/doc/snippets/cmake-macros/examples.cmake new file mode 100644 index 0000000000..bba082586f --- /dev/null +++ b/src/corelib/doc/snippets/cmake-macros/examples.cmake @@ -0,0 +1,26 @@ +#! [qt5_wrap_cpp] +set(SOURCES myapp.cpp main.cpp) +qt5_wrap_cpp(SOURCES myapp.h) +add_executable(myapp ${SOURCES}) +#! [qt5_wrap_cpp] + +#! [qt5_add_resources] +set(SOURCES main.cpp) +qt5_add_resources(SOURCES example.qrc) +add_executable(myapp ${SOURCES}) +#! [qt5_add_resources] + +#! [qt5_add_big_resources] +set(SOURCES main.cpp) +qt5_add_big_resources(SOURCES big_resource.qrc) +add_executable(myapp ${SOURCES}) +#! [qt5_add_big_resources] + +#! [qt5_add_binary_resources] +qt5_add_binary_resources(resources project.qrc OPTIONS -no-compress) +add_dependencies(myapp resources) +#! [qt5_add_binary_resources] + +#! [qt5_generate_moc] +qt5_generate_moc(main.cpp main.moc TARGET myapp) +#! [qt5_generate_moc] diff --git a/src/corelib/doc/src/cmake-macros.qdoc b/src/corelib/doc/src/cmake-macros.qdoc new file mode 100644 index 0000000000..6140e8be44 --- /dev/null +++ b/src/corelib/doc/src/cmake-macros.qdoc @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtcore-cmake-qt5-wrap-cpp.html +\ingroup cmake-macros-qtcore + +\title qt5_wrap_cpp + +\brief Creates \c{.moc} files from sources. + +\section1 Synopsis + +\badcode +qt5_wrap_cpp(<VAR> src_file1 [src_file2 ...] + [TARGET target] + [OPTIONS ...] + [DEPENDS ...]) +\endcode + +\section1 Description + +Creates rules for calling \l{moc}{Meta-Object Compiler (moc)} on the given +source files. For each input file, an output file is generated in the build +directory. The paths of the generated files are added to\c{<VAR>}. + +\note This is a low-level macro. See the \l{CMake AUTOMOC Documentation} for a +more convenient way to let source files be processed with \c{moc}. + +\section1 Options + +You can set an explicit \c{TARGET}. This will make sure that the target +properties \c{INCLUDE_DIRECTORIES} and \c{COMPILE_DEFINITIONS} are also used +when scanning the source files with \c{moc}. + +You can set additional \c{OPTIONS} that should be added to the \c{moc} calls. +You can find possible options in the \l{moc}{moc documentation}. + +\c{DEPENDS} allows you to add additional dependencies for recreation of the +generated files. This is useful when the sources have implicit dependencies, +like code for a Qt plugin that includes a \c{.json} file using the +Q_PLUGIN_METADATA() macro. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_wrap_cpp +*/ + +/*! +\page qtcore-cmake-qt5-add-resources.html +\ingroup cmake-macros-qtcore + +\title qt5_add_resources + +\brief Compiles binary resources into source code. + +\section1 Synopsis + +\badcode +qt5_add_resources(<VAR> file1.qrc [file2.qrc ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Creates source code from Qt resource files using the +\l{Resource Compiler (rcc)}. Paths to the generated source files are added to +\c{<VAR>}. + +\note This is a low-level macro. See the \l{CMake AUTORCC Documentation} for a +more convenient way to let Qt resource files be processed with \c{rcc}. +For embedding bigger resources, see \l qt5_add_big_resources. + +\section1 Arguments + +You can set additional \c{OPTIONS} that should be added to the \c{rcc} calls. +You can find possible options in the \l{rcc}{rcc documentation}. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_add_resources +*/ + +/*! +\page qtcore-cmake-qt5-add-big-resources.html +\ingroup cmake-macros-qtcore + +\title qt5_add_big_resources + +\brief Compiles big binary resources into object code. + +\section1 Synopsis + +\badcode +qt5_add_big_resources(<VAR> file1.qrc [file2.qrc ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Creates compiled object files from Qt resource files using the +\l{Resource Compiler (rcc)}. Paths to the generated files are added to +\c{<VAR>}. + +This is similar to \l qt5_add_resources, but directly generates object +files (\c .o, \c .obj) files instead of C++ source code. This allows to +embed bigger resources, where compiling to C++ sources and then to +binaries would be too time consuming or memory intensive. + +\section1 Arguments + +You can set additional \c{OPTIONS} that should be added to the \c{rcc} calls. +You can find possible options in the \l{rcc}{rcc documentation}. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_add_big_resources +*/ + +/*! +\page qtcore-cmake-qt5_add_binary_resources.html +\ingroup cmake-macros-qtcore + +\title qt5_add_binary_resources + +\brief Creates an \c{RCC} file from a list of Qt resource files. + +\section1 Synopsis + +\badcode +qt5_add_binary_resources(target file1.qrc [file2.qrc ...] + [DESTINATION ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Adds a custom \c target that compiles Qt resource files into a binary \c{.rcc} +file. + +\section1 Arguments + +\c{DESTINATION} sets the path of the generated \c{.rcc} file. The default is +\c{${CMAKE_CURRENT_BINARY_DIR}/${target}.rcc}. + +You can set additional \c{OPTIONS} that should be added to the \c{rcc} calls. +You can find possible options in the \l{rcc}{rcc documentation}. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_add_binary_resources +*/ + +/*! +\page qtcore-cmake-qt5-generate-moc.html +\ingroup cmake-macros-qtcore + +\title qt5_generate_moc + +\brief Calls moc on an input file. + +\section1 Synopsis + +\badcode +qt5_generate_moc(src_file dest_file + [TARGET target]) +\endcode + +\section1 Description + +Creates a rule to call the \l{moc}{Meta-Object Compiler (moc)} on \c src_file +and store the output in \c dest_file. + +\note This is a low-level macro. See the \l{CMake AUTOMOC Documentation} for a +more convenient way to let source files be processed with \c{moc}. +\l qt5_wrap_cpp is also similar, but automatically generates a temporary file +path for you. + +\section1 Arguments + +You can set an explicit \c{TARGET}. This will make sure that the target +properties \c{INCLUDE_DIRECTORIES} and \c{COMPILE_DEFINITIONS} are also used +when scanning the source files with \c{moc}. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_generate_moc +*/ diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h index 51ace3d5f7..1efb49017f 100644 --- a/src/corelib/kernel/qmetaobject.h +++ b/src/corelib/kernel/qmetaobject.h @@ -230,7 +230,8 @@ public: template<typename T> static QMetaEnum fromType() { Q_STATIC_ASSERT_X(QtPrivate::IsQEnumHelper<T>::Value, - "QMetaEnum::fromType only works with enums declared as Q_ENUM or Q_FLAG"); + "QMetaEnum::fromType only works with enums declared as " + "Q_ENUM, Q_ENUM_NS, Q_FLAG or Q_FLAG_NS"); const QMetaObject *metaObject = qt_getEnumMetaObject(T()); const char *name = qt_getEnumName(T()); return metaObject->enumerator(metaObject->indexOfEnumerator(name)); diff --git a/src/gui/kernel/qhighdpiscaling.cpp b/src/gui/kernel/qhighdpiscaling.cpp index 4b85973e92..4f8e9a3817 100644 --- a/src/gui/kernel/qhighdpiscaling.cpp +++ b/src/gui/kernel/qhighdpiscaling.cpp @@ -492,5 +492,13 @@ QPoint QHighDpiScaling::origin(const QPlatformScreen *platformScreen) return platformScreen->geometry().topLeft(); } +QPoint QHighDpiScaling::origin(const QWindow *window) +{ + if (window && window->isTopLevel() && window->screen()) + return window->screen()->geometry().topLeft(); + + return QPoint(0, 0); +} + #endif //QT_NO_HIGHDPISCALING QT_END_NAMESPACE diff --git a/src/gui/kernel/qhighdpiscaling_p.h b/src/gui/kernel/qhighdpiscaling_p.h index 28cf7de75b..dfc6abf5ba 100644 --- a/src/gui/kernel/qhighdpiscaling_p.h +++ b/src/gui/kernel/qhighdpiscaling_p.h @@ -83,6 +83,7 @@ public: static qreal factor(const QPlatformScreen *platformScreen); static QPoint origin(const QScreen *screen); static QPoint origin(const QPlatformScreen *platformScreen); + static QPoint origin(const QWindow *window); static QPoint mapPositionToNative(const QPoint &pos, const QPlatformScreen *platformScreen); static QPoint mapPositionFromNative(const QPoint &pos, const QPlatformScreen *platformScreen); static QPoint mapPositionToGlobal(const QPoint &pos, const QPoint &windowGlobalPosition, const QWindow *window); @@ -203,94 +204,42 @@ inline QPointF toNativeLocalPosition(const QPointF &pos, const QWindow *window) return pos * scaleFactor; } -inline QRect fromNativePixels(const QRect &pixelRect, const QPlatformScreen *platformScreen) +template <typename C> +inline QRect fromNativePixels(const QRect &pixelRect, const C *context) { - const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); - const QPoint origin = QHighDpiScaling::origin(platformScreen); + const qreal scaleFactor = QHighDpiScaling::factor(context); + const QPoint origin = QHighDpiScaling::origin(context); return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), fromNative(pixelRect.size(), scaleFactor)); } -inline QRect toNativePixels(const QRect &pointRect, const QPlatformScreen *platformScreen) +template <typename C> +inline QRect toNativePixels(const QRect &pointRect, const C *context) { - const qreal scaleFactor = QHighDpiScaling::factor(platformScreen); - const QPoint origin = QHighDpiScaling::origin(platformScreen); + const qreal scaleFactor = QHighDpiScaling::factor(context); + const QPoint origin = QHighDpiScaling::origin(context); return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), toNative(pointRect.size(), scaleFactor)); } -inline QRect fromNativePixels(const QRect &pixelRect, const QScreen *screen) +template <typename C> +inline QRectF toNativePixels(const QRectF &pointRect, const C *context) { - const qreal scaleFactor = QHighDpiScaling::factor(screen); - const QPoint origin = QHighDpiScaling::origin(screen); - return QRect(fromNative(pixelRect.topLeft(), scaleFactor, origin), - fromNative(pixelRect.size(), scaleFactor)); -} - -inline QRect toNativePixels(const QRect &pointRect, const QScreen *screen) -{ - const qreal scaleFactor = QHighDpiScaling::factor(screen); - const QPoint origin = QHighDpiScaling::origin(screen); - return QRect(toNative(pointRect.topLeft(), scaleFactor, origin), - toNative(pointRect.size(), scaleFactor)); -} - -inline QRect fromNativePixels(const QRect &pixelRect, const QWindow *window) -{ - if (window && window->isTopLevel() && window->screen()) { - return fromNativePixels(pixelRect, window->screen()); - } else { - const qreal scaleFactor = QHighDpiScaling::factor(window); - return QRect(pixelRect.topLeft() / scaleFactor, fromNative(pixelRect.size(), scaleFactor)); - } -} - -inline QRectF toNativePixels(const QRectF &pointRect, const QScreen *screen) -{ - const qreal scaleFactor = QHighDpiScaling::factor(screen); - const QPoint origin = QHighDpiScaling::origin(screen); + const qreal scaleFactor = QHighDpiScaling::factor(context); + const QPoint origin = QHighDpiScaling::origin(context); return QRectF(toNative(pointRect.topLeft(), scaleFactor, origin), - toNative(pointRect.size(), scaleFactor)); + toNative(pointRect.size(), scaleFactor)); } -inline QRect toNativePixels(const QRect &pointRect, const QWindow *window) +template <typename C> +inline QRectF fromNativePixels(const QRectF &pixelRect, const C *context) { - if (window && window->isTopLevel() && window->screen()) { - return toNativePixels(pointRect, window->screen()); - } else { - const qreal scaleFactor = QHighDpiScaling::factor(window); - return QRect(pointRect.topLeft() * scaleFactor, toNative(pointRect.size(), scaleFactor)); - } -} - -inline QRectF fromNativePixels(const QRectF &pixelRect, const QScreen *screen) -{ - const qreal scaleFactor = QHighDpiScaling::factor(screen); - const QPoint origin = QHighDpiScaling::origin(screen); + const qreal scaleFactor = QHighDpiScaling::factor(context); + const QPoint origin = QHighDpiScaling::origin(context); return QRectF(fromNative(pixelRect.topLeft(), scaleFactor, origin), fromNative(pixelRect.size(), scaleFactor)); } -inline QRectF fromNativePixels(const QRectF &pixelRect, const QWindow *window) -{ - if (window && window->isTopLevel() && window->screen()) { - return fromNativePixels(pixelRect, window->screen()); - } else { - const qreal scaleFactor = QHighDpiScaling::factor(window); - return QRectF(pixelRect.topLeft() / scaleFactor, pixelRect.size() / scaleFactor); - } -} - -inline QRectF toNativePixels(const QRectF &pointRect, const QWindow *window) -{ - if (window && window->isTopLevel() && window->screen()) { - return toNativePixels(pointRect, window->screen()); - } else { - const qreal scaleFactor = QHighDpiScaling::factor(window); - return QRectF(pointRect.topLeft() * scaleFactor, pointRect.size() * scaleFactor); - } -} - inline QSize fromNativePixels(const QSize &pixelSize, const QWindow *window) { return pixelSize / QHighDpiScaling::factor(window); @@ -311,56 +260,28 @@ inline QSizeF toNativePixels(const QSizeF &pointSize, const QWindow *window) return pointSize * QHighDpiScaling::factor(window); } -inline QPoint fromNativePixels(const QPoint &pixelPoint, const QScreen *screen) +template <typename C> +inline QPoint fromNativePixels(const QPoint &pixelPoint, const C *context) { - return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); + return fromNative(pixelPoint, QHighDpiScaling::factor(context), QHighDpiScaling::origin(context)); } -inline QPoint fromNativePixels(const QPoint &pixelPoint, const QWindow *window) +template <typename C> +inline QPoint toNativePixels(const QPoint &pointPoint, const C *context) { - if (window && window->isTopLevel() && window->screen()) - return fromNativePixels(pixelPoint, window->screen()); - else - return pixelPoint / QHighDpiScaling::factor(window); + return toNative(pointPoint, QHighDpiScaling::factor(context), QHighDpiScaling::origin(context)); } -inline QPoint toNativePixels(const QPoint &pointPoint, const QScreen *screen) +template <typename C> +inline QPointF fromNativePixels(const QPointF &pixelPoint, const C *context) { - return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); + return fromNative(pixelPoint, QHighDpiScaling::factor(context), QHighDpiScaling::origin(context)); } -inline QPoint toNativePixels(const QPoint &pointPoint, const QWindow *window) +template <typename C> +inline QPointF toNativePixels(const QPointF &pointPoint, const C *context) { - if (window && window->isTopLevel() && window->screen()) - return toNativePixels(pointPoint, window->screen()); - else - return pointPoint * QHighDpiScaling::factor(window); -} - -inline QPointF fromNativePixels(const QPointF &pixelPoint, const QScreen *screen) -{ - return fromNative(pixelPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); -} - -inline QPointF fromNativePixels(const QPointF &pixelPoint, const QWindow *window) -{ - if (window && window->isTopLevel() && window->screen()) - return fromNativePixels(pixelPoint, window->screen()); - else - return pixelPoint / QHighDpiScaling::factor(window); -} - -inline QPointF toNativePixels(const QPointF &pointPoint, const QScreen *screen) -{ - return toNative(pointPoint, QHighDpiScaling::factor(screen), QHighDpiScaling::origin(screen)); -} - -inline QPointF toNativePixels(const QPointF &pointPoint, const QWindow *window) -{ - if (window && window->isTopLevel() && window->screen()) - return toNativePixels(pointPoint, window->screen()); - else - return pointPoint * QHighDpiScaling::factor(window); + return toNative(pointPoint, QHighDpiScaling::factor(context), QHighDpiScaling::origin(context)); } inline QMargins fromNativePixels(const QMargins &pixelMargins, const QWindow *window) @@ -425,47 +346,26 @@ inline QRegion toNativeLocalRegion(const QRegion &pointRegion, const QWindow *wi } // Any T that has operator/() -template <typename T> -T fromNativePixels(const T &pixelValue, const QWindow *window) -{ - if (!QHighDpiScaling::isActive()) - return pixelValue; - - return pixelValue / QHighDpiScaling::factor(window); - -} - - //##### ????? -template <typename T> -T fromNativePixels(const T &pixelValue, const QScreen *screen) +template <typename T, typename C> +T fromNativePixels(const T &pixelValue, const C *context) { if (!QHighDpiScaling::isActive()) return pixelValue; - return pixelValue / QHighDpiScaling::factor(screen); + return pixelValue / QHighDpiScaling::factor(context); } // Any T that has operator*() -template <typename T> -T toNativePixels(const T &pointValue, const QWindow *window) -{ - if (!QHighDpiScaling::isActive()) - return pointValue; - - return pointValue * QHighDpiScaling::factor(window); -} - -template <typename T> -T toNativePixels(const T &pointValue, const QScreen *screen) +template <typename T, typename C> +T toNativePixels(const T &pointValue, const C *context) { if (!QHighDpiScaling::isActive()) return pointValue; - return pointValue * QHighDpiScaling::factor(screen); + return pointValue * QHighDpiScaling::factor(context); } - // Any QVector<T> where T has operator/() template <typename T> QVector<T> fromNativePixels(const QVector<T> &pixelValues, const QWindow *window) diff --git a/src/gui/kernel/qplatformwindow.cpp b/src/gui/kernel/qplatformwindow.cpp index 562289a8c9..4e95751397 100644 --- a/src/gui/kernel/qplatformwindow.cpp +++ b/src/gui/kernel/qplatformwindow.cpp @@ -705,14 +705,20 @@ QRect QPlatformWindow::initialGeometry(const QWindow *w, w, defaultWidth, defaultHeight); return QRect(initialGeometry.topLeft(), QHighDpi::toNative(size, factor)); } - const QScreen *screen = effectiveScreen(w); + const auto *wp = qt_window_private(const_cast<QWindow*>(w)); + const bool position = wp->positionAutomatic && w->type() != Qt::Popup; + if (!position && !wp->resizeAutomatic) + return initialGeometry; + const QScreen *screen = wp->positionAutomatic + ? effectiveScreen(w) + : QGuiApplication::screenAt(initialGeometry.center()); if (!screen) return initialGeometry; - const auto *wp = qt_window_private(const_cast<QWindow*>(w)); + // initialGeometry refers to window's screen QRect rect(QHighDpi::fromNativePixels(initialGeometry, w)); if (wp->resizeAutomatic) rect.setSize(fixInitialSize(rect.size(), w, defaultWidth, defaultHeight)); - if (wp->positionAutomatic && w->type() != Qt::Popup) { + if (position) { const QRect availableGeometry = screen->availableGeometry(); // Center unless the geometry ( + unknown window frame) is too large for the screen). if (rect.height() < (availableGeometry.height() * 8) / 9 diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp index a62e7e425a..9721243454 100644 --- a/src/gui/text/qtextodfwriter.cpp +++ b/src/gui/text/qtextodfwriter.cpp @@ -43,6 +43,7 @@ #include "qtextodfwriter_p.h" +#include <QImageReader> #include <QImageWriter> #include <QTextListFormat> #include <QTextList> @@ -410,6 +411,29 @@ void QTextOdfWriter::writeBlock(QXmlStreamWriter &writer, const QTextBlock &bloc writer.writeEndElement(); // list-item } +static bool probeImageData(QIODevice *device, QImage *image, QString *mimeType, qreal *width, qreal *height) +{ + QImageReader reader(device); + const QByteArray format = reader.format().toLower(); + if (format == "png") { + *mimeType = QStringLiteral("image/png"); + } else if (format == "jpg") { + *mimeType = QStringLiteral("image/jpg"); + } else if (format == "svg") { + *mimeType = QStringLiteral("image/svg+xml"); + } else { + *image = reader.read(); + return false; + } + + const QSize size = reader.size(); + + *width = size.width(); + *height = size.height(); + + return true; +} + void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextFragment &fragment) const { writer.writeStartElement(drawNS, QString::fromLatin1("frame")); @@ -420,47 +444,73 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF QTextImageFormat imageFormat = fragment.charFormat().toImageFormat(); writer.writeAttribute(drawNS, QString::fromLatin1("name"), imageFormat.name()); + QByteArray data; + QString mimeType; + qreal width = 0; + qreal height = 0; + QImage image; QString name = imageFormat.name(); if (name.startsWith(QLatin1String(":/"))) // auto-detect resources name.prepend(QLatin1String("qrc")); QUrl url = QUrl(name); - const QVariant data = m_document->resource(QTextDocument::ImageResource, url); - if (data.type() == QVariant::Image) { - image = qvariant_cast<QImage>(data); - } else if (data.type() == QVariant::ByteArray) { - image.loadFromData(data.toByteArray()); - } - - if (image.isNull()) { - if (image.isNull()) { // try direct loading - name = imageFormat.name(); // remove qrc:/ prefix again - image.load(name); + const QVariant variant = m_document->resource(QTextDocument::ImageResource, url); + if (variant.type() == QVariant::Image) { + image = qvariant_cast<QImage>(variant); + } else if (variant.type() == QVariant::ByteArray) { + data = variant.toByteArray(); + + QBuffer buffer(&data); + buffer.open(QIODevice::ReadOnly); + probeImageData(&buffer, &image, &mimeType, &width, &height); + } else { + // try direct loading + QFile file(imageFormat.name()); + if (file.open(QIODevice::ReadOnly) && !probeImageData(&file, &image, &mimeType, &width, &height)) { + file.seek(0); + data = file.readAll(); } } if (! image.isNull()) { QBuffer imageBytes; - QString filename = m_strategy->createUniqueImageName(); + int imgQuality = imageFormat.quality(); if (imgQuality >= 100 || imgQuality < 0 || image.hasAlphaChannel()) { QImageWriter imageWriter(&imageBytes, "png"); imageWriter.write(image); - m_strategy->addFile(filename, QString::fromLatin1("image/png"), imageBytes.data()); + + data = imageBytes.data(); + mimeType = QStringLiteral("image/png"); } else { // Write images without alpha channel as jpg with quality set by QTextImageFormat QImageWriter imageWriter(&imageBytes, "jpg"); imageWriter.setQuality(imgQuality); imageWriter.write(image); - m_strategy->addFile(filename, QString::fromLatin1("image/jpg"), imageBytes.data()); + + data = imageBytes.data(); + mimeType = QStringLiteral("image/jpg"); } - // get the width/height from the format. - qreal width = imageFormat.hasProperty(QTextFormat::ImageWidth) - ? imageFormat.width() : image.width(); + + width = image.width(); + height = image.height(); + } + + if (!data.isEmpty()) { + if (imageFormat.hasProperty(QTextFormat::ImageWidth)) { + width = imageFormat.width(); + } + if (imageFormat.hasProperty(QTextFormat::ImageHeight)) { + height = imageFormat.height(); + } + + QString filename = m_strategy->createUniqueImageName(); + + m_strategy->addFile(filename, mimeType, data); + writer.writeAttribute(svgNS, QString::fromLatin1("width"), pixelToPoint(width)); - qreal height = imageFormat.hasProperty(QTextFormat::ImageHeight) - ? imageFormat.height() : image.height(); writer.writeAttribute(svgNS, QString::fromLatin1("height"), pixelToPoint(height)); + writer.writeAttribute(textNS, QStringLiteral("anchor-type"), QStringLiteral("as-char")); writer.writeStartElement(drawNS, QString::fromLatin1("image")); writer.writeAttribute(xlinkNS, QString::fromLatin1("href"), filename); writer.writeEndElement(); // image diff --git a/src/platformsupport/clipboard/qmacmime.mm b/src/platformsupport/clipboard/qmacmime.mm index f425e34b39..76e9c8712c 100644 --- a/src/platformsupport/clipboard/qmacmime.mm +++ b/src/platformsupport/clipboard/qmacmime.mm @@ -435,8 +435,23 @@ QList<QByteArray> QMacPasteboardMimeUnicodeText::convertFromMime(const QString & if (flavor == QLatin1String("public.utf8-plain-text")) ret.append(string.toUtf8()); #if QT_CONFIG(textcodec) - else if (flavor == QLatin1String("public.utf16-plain-text")) - ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode(string)); + else if (flavor == QLatin1String("public.utf16-plain-text")) { + QTextCodec::ConverterState state; +#if defined(Q_OS_MACOS) + // Some applications such as Microsoft Excel, don't deal well with + // a BOM present, so we follow the traditional approach of Qt on + // macOS to not generate public.utf16-plain-text with a BOM. + state.flags = QTextCodec::IgnoreHeader; +#else + // Whereas iOS applications will fail to paste if we do _not_ + // include a BOM in the public.utf16-plain-text content, most + // likely due to converting the data using NSUTF16StringEncoding + // which assumes big-endian byte order if there is no BOM. + state.flags = QTextCodec::DefaultConversion; +#endif + ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode( + string.constData(), string.length(), &state)); + } #endif return ret; } diff --git a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h index 64c54c694a..fd39b6ee33 100644 --- a/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h +++ b/src/platformsupport/windowsuiautomation/uiaserverinterfaces_p.h @@ -360,4 +360,27 @@ __CRT_UUID_DECL(IGridItemProvider, 0xd02541f1, 0xfb81, 0x4d64, 0xae,0x32, 0xf5,0 #endif #endif + +#ifndef __IWindowProvider_INTERFACE_DEFINED__ +#define __IWindowProvider_INTERFACE_DEFINED__ +DEFINE_GUID(IID_IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa9,0xc3,0xbb,0x90,0xb9); +MIDL_INTERFACE("987df77b-db06-4d77-8f8a-86a9c3bb90b9") +IWindowProvider : public IUnknown +{ +public: + virtual HRESULT STDMETHODCALLTYPE SetVisualState(enum WindowVisualState state) = 0; + virtual HRESULT STDMETHODCALLTYPE Close( void) = 0; + virtual HRESULT STDMETHODCALLTYPE WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_CanMaximize(__RPC__out BOOL *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_CanMinimize(__RPC__out BOOL *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_IsModal(__RPC__out BOOL *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_WindowVisualState(__RPC__out enum WindowVisualState *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_WindowInteractionState(__RPC__out enum WindowInteractionState *pRetVal) = 0; + virtual HRESULT STDMETHODCALLTYPE get_IsTopmost(__RPC__out BOOL *pRetVal) = 0; +}; +#ifdef __CRT_UUID_DECL +__CRT_UUID_DECL(IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f,0x8a, 0x86,0xa9,0xc3,0xbb,0x90,0xb9) +#endif +#endif + #endif diff --git a/src/platformsupport/windowsuiautomation/uiatypes_p.h b/src/platformsupport/windowsuiautomation/uiatypes_p.h index ea58417943..8ef71843a3 100644 --- a/src/platformsupport/windowsuiautomation/uiatypes_p.h +++ b/src/platformsupport/windowsuiautomation/uiatypes_p.h @@ -141,6 +141,20 @@ enum PropertyConditionFlags { PropertyConditionFlags_IgnoreCase = 1 }; +enum WindowVisualState { + WindowVisualState_Normal = 0, + WindowVisualState_Maximized = 1, + WindowVisualState_Minimized = 2 +}; + +enum WindowInteractionState { + WindowInteractionState_Running = 0, + WindowInteractionState_Closing = 1, + WindowInteractionState_ReadyForUserInteraction = 2, + WindowInteractionState_BlockedByModalWindow = 3, + WindowInteractionState_NotResponding = 4 +}; + struct UiaRect { double left; double top; diff --git a/src/plugins/platforms/android/qandroidinputcontext.cpp b/src/plugins/platforms/android/qandroidinputcontext.cpp index 07a6b52dbe..db40c30d7d 100644 --- a/src/plugins/platforms/android/qandroidinputcontext.cpp +++ b/src/plugins/platforms/android/qandroidinputcontext.cpp @@ -1129,46 +1129,63 @@ QString QAndroidInputContext::getSelectedText(jint /*flags*/) QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/) { - //### the preedit text could theoretically be after the cursor - QVariant textAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, QVariant(length)); - if (textAfter.isValid()) { - return textAfter.toString().left(length); - } - - //compatibility code for old controls that do not implement the new API - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - if (query.isNull()) + if (length <= 0) return QString(); - QString text = query->value(Qt::ImSurroundingText).toString(); - if (!text.length()) - return text; + QString text; - int cursorPos = query->value(Qt::ImCursorPosition).toInt(); - return text.mid(cursorPos, length); + QVariant reportedTextAfter = QInputMethod::queryFocusObject(Qt::ImTextAfterCursor, length); + if (reportedTextAfter.isValid()) { + text = reportedTextAfter.toString(); + } else { + // Compatibility code for old controls that do not implement the new API + QSharedPointer<QInputMethodQueryEvent> query = + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText); + if (query) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); + text = query->value(Qt::ImSurroundingText).toString().mid(cursorPos); + } + } + + // Controls do not report preedit text, so we have to add it + if (!m_composingText.isEmpty()) { + const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart; + text = m_composingText.midRef(cursorPosInsidePreedit) + text; + } + + text.truncate(length); + return text; } QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/) { - QVariant textBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, QVariant(length)); - if (textBefore.isValid()) - return textBefore.toString().rightRef(length) + m_composingText; - - //compatibility code for old controls that do not implement the new API - QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(); - if (query.isNull()) + if (length <= 0) return QString(); - int cursorPos = query->value(Qt::ImCursorPosition).toInt(); - QString text = query->value(Qt::ImSurroundingText).toString(); - if (!text.length()) - return text; + QString text; - //### the preedit text does not need to be immediately before the cursor - if (cursorPos <= length) - return text.leftRef(cursorPos) + m_composingText; - else - return text.midRef(cursorPos - length, length) + m_composingText; + QVariant reportedTextBefore = QInputMethod::queryFocusObject(Qt::ImTextBeforeCursor, length); + if (reportedTextBefore.isValid()) { + text = reportedTextBefore.toString(); + } else { + // Compatibility code for old controls that do not implement the new API + QSharedPointer<QInputMethodQueryEvent> query = + focusObjectInputMethodQuery(Qt::ImCursorPosition | Qt::ImSurroundingText); + if (query) { + const int cursorPos = query->value(Qt::ImCursorPosition).toInt(); + text = query->value(Qt::ImSurroundingText).toString().left(cursorPos); + } + } + + // Controls do not report preedit text, so we have to add it + if (!m_composingText.isEmpty()) { + const int cursorPosInsidePreedit = m_composingCursor - m_composingTextStart; + text += m_composingText.leftRef(cursorPosInsidePreedit); + } + + if (text.length() > length) + text = text.right(length); + return text; } /* @@ -1231,6 +1248,8 @@ jboolean QAndroidInputContext::setComposingRegion(jint start, jint end) if (query.isNull()) return JNI_FALSE; + if (start == end) + return JNI_TRUE; if (start > end) qSwap(start, end); diff --git a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp index 738c30c65a..b8f04cf978 100644 --- a/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp +++ b/src/plugins/platforms/eglfs/deviceintegration/eglfs_openwfd/qeglfsopenwfdintegration.cpp @@ -221,7 +221,7 @@ EGLNativeWindowType QEglFSOpenWFDIntegration::createNativeWindow(QPlatformWindow QSurfaceFormat QEglFSOpenWFDIntegration::surfaceFormatFor(const QSurfaceFormat &inputFormat) const { - QSurfaceFormat format; + QSurfaceFormat format = inputFormat; format.setRedBufferSize(8); format.setGreenBufferSize(8); format.setBlueBufferSize(8); diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 281f18af5b..55e7e32979 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1488,6 +1488,10 @@ void QWindowsContext::handleExitSizeMove(QWindow *window) keyboardModifiers); } } + if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) + d->m_pointerHandler.clearEvents(); + else + d->m_mouseHandler.clearEvents(); } bool QWindowsContext::asyncExpose() const diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 737fd1d2a9..e33591c33d 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -157,6 +157,12 @@ QTouchDevice *QWindowsMouseHandler::ensureTouchDevice() return m_touchDevice; } +void QWindowsMouseHandler::clearEvents() +{ + m_lastEventType = QEvent::None; + m_lastEventButton = Qt::NoButton; +} + Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons() { Qt::MouseButtons result = nullptr; @@ -287,8 +293,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; - const MouseEvent mouseEvent = eventFromMsg(msg); - // Check for events synthesized from touch. Lower byte is touch index, 0 means pen. static const bool passSynthesizedMouseEvents = !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch); @@ -305,13 +309,40 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } } + const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers(); + const MouseEvent mouseEvent = eventFromMsg(msg); + Qt::MouseButtons buttons; + + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) + buttons = queryMouseButtons(); + else + buttons = keyStateToMouseButtons(msg.wParam); + + // When the left/right mouse buttons are pressed over the window title bar + // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP + // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE. + // We detect it and generate the missing release events here. (QTBUG-75678) + // The last event vars are cleared on QWindowsContext::handleExitSizeMove() + // to avoid generating duplicated release events. + if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress + && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove) + && (m_lastEventButton & buttons) == 0) { + if (mouseEvent.type == QEvent::NonClientAreaMouseMove) { + QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton, + QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source); + } else { + QWindowSystemInterface::handleMouseEvent(window, clientPosition, globalPosition, buttons, m_lastEventButton, + QEvent::MouseButtonRelease, keyModifiers, source); + } + } + m_lastEventType = mouseEvent.type; + m_lastEventButton = mouseEvent.button; + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { - const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, mouseEvent.button, mouseEvent.type, - QWindowsKeyMapper::queryKeyboardModifiers(), - source); + keyModifiers, source); return false; // Allow further event processing (dragging of windows). } @@ -334,7 +365,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle()); - const Qt::MouseButtons buttons = keyStateToMouseButtons(int(msg.wParam)); // 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, @@ -461,8 +491,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, if (!discardEvent && mouseEvent.type != QEvent::None) { QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, mouseEvent.button, mouseEvent.type, - QWindowsKeyMapper::queryKeyboardModifiers(), - source); + keyModifiers, source); } m_previousCaptureWindow = hasCapture ? window : nullptr; // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.h b/src/plugins/platforms/windows/qwindowsmousehandler.h index 480662c9bf..5fe4b09c1e 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.h +++ b/src/plugins/platforms/windows/qwindowsmousehandler.h @@ -45,6 +45,7 @@ #include <QtCore/qpointer.h> #include <QtCore/qhash.h> +#include <QtGui/qevent.h> QT_BEGIN_NAMESPACE @@ -72,13 +73,14 @@ public: bool translateScrollEvent(QWindow *window, HWND hwnd, MSG msg, LRESULT *result); - static inline Qt::MouseButtons keyStateToMouseButtons(int); + static inline Qt::MouseButtons keyStateToMouseButtons(WPARAM); static inline Qt::KeyboardModifiers keyStateToModifiers(int); static inline int mouseButtonsToKeyState(Qt::MouseButtons); static Qt::MouseButtons queryMouseButtons(); QWindow *windowUnderMouse() const { return m_windowUnderMouse.data(); } void clearWindowUnderMouse() { m_windowUnderMouse = 0; } + void clearEvents(); private: inline bool translateMouseWheelEvent(QWindow *window, HWND hwnd, @@ -91,9 +93,11 @@ private: QTouchDevice *m_touchDevice = nullptr; bool m_leftButtonDown = false; QWindow *m_previousCaptureWindow = nullptr; + QEvent::Type m_lastEventType = QEvent::None; + Qt::MouseButton m_lastEventButton = Qt::NoButton; }; -Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(int wParam) +Qt::MouseButtons QWindowsMouseHandler::keyStateToMouseButtons(WPARAM wParam) { Qt::MouseButtons mb(Qt::NoButton); if (wParam & MK_LBUTTON) diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index 501b62e07a..fd3d711470 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -336,6 +336,12 @@ QTouchDevice *QWindowsPointerHandler::ensureTouchDevice() return m_touchDevice; } +void QWindowsPointerHandler::clearEvents() +{ + m_lastEventType = QEvent::None; + m_lastEventButton = Qt::NoButton; +} + void QWindowsPointerHandler::handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, @@ -726,10 +732,35 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, } const MouseEvent mouseEvent = eventFromMsg(msg); + Qt::MouseButtons mouseButtons; + + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) + mouseButtons = queryMouseButtons(); + else + mouseButtons = mouseButtonsFromKeyState(msg.wParam); + + // When the left/right mouse buttons are pressed over the window title bar + // WM_NCLBUTTONDOWN/WM_NCRBUTTONDOWN messages are received. But no UP + // messages are received on release, only WM_NCMOUSEMOVE/WM_MOUSEMOVE. + // We detect it and generate the missing release events here. (QTBUG-75678) + // The last event vars are cleared on QWindowsContext::handleExitSizeMove() + // to avoid generating duplicated release events. + if (m_lastEventType == QEvent::NonClientAreaMouseButtonPress + && (mouseEvent.type == QEvent::NonClientAreaMouseMove || mouseEvent.type == QEvent::MouseMove) + && (m_lastEventButton & mouseButtons) == 0) { + if (mouseEvent.type == QEvent::NonClientAreaMouseMove) { + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton, + QEvent::NonClientAreaMouseButtonRelease, keyModifiers, source); + } else { + QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, m_lastEventButton, + QEvent::MouseButtonRelease, keyModifiers, source); + } + } + m_lastEventType = mouseEvent.type; + m_lastEventButton = mouseEvent.button; if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { - const Qt::MouseButtons nonclientButtons = queryMouseButtons(); - QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, nonclientButtons, + QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, mouseEvent.button, mouseEvent.type, keyModifiers, source); return false; // Allow further event processing } @@ -745,8 +776,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, return true; } - const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam); - handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons); handleEnterLeave(window, currentWindowUnderPointer, globalPos); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h index aebef062bc..ccbb1d3939 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.h +++ b/src/plugins/platforms/windows/qwindowspointerhandler.h @@ -46,7 +46,7 @@ #include <QtCore/qpointer.h> #include <QtCore/qscopedpointer.h> #include <QtCore/qhash.h> -#include <qpa/qwindowsysteminterface.h> +#include <QtGui/qevent.h> QT_BEGIN_NAMESPACE @@ -64,6 +64,7 @@ public: QTouchDevice *ensureTouchDevice(); QWindow *windowUnderMouse() const { return m_windowUnderPointer.data(); } void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; } + void clearEvents(); private: bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count); @@ -79,6 +80,8 @@ private: QPointer<QWindow> m_currentWindow; QWindow *m_previousCaptureWindow = nullptr; bool m_needsEnterOnPointerUpdate = false; + QEvent::Type m_lastEventType = QEvent::None; + Qt::MouseButton m_lastEventButton = Qt::NoButton; }; QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp index 44328492a6..a427e553f0 100644 --- a/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiamainprovider.cpp @@ -52,6 +52,7 @@ #include "qwindowsuiatableitemprovider.h" #include "qwindowsuiagridprovider.h" #include "qwindowsuiagriditemprovider.h" +#include "qwindowsuiawindowprovider.h" #include "qwindowscombase.h" #include "qwindowscontext.h" #include "qwindowsuiautils.h" @@ -263,6 +264,11 @@ HRESULT QWindowsUiaMainProvider::GetPatternProvider(PATTERNID idPattern, IUnknow return UIA_E_ELEMENTNOTAVAILABLE; switch (idPattern) { + case UIA_WindowPatternId: + if (accessible->parent() && (accessible->parent()->role() == QAccessible::Application)) { + *pRetVal = new QWindowsUiaWindowProvider(id()); + } + break; case UIA_TextPatternId: case UIA_TextPattern2Id: // All text controls. @@ -352,8 +358,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR if (!accessible) return UIA_E_ELEMENTNOTAVAILABLE; - bool clientTopLevel = (accessible->role() == QAccessible::Client) - && accessible->parent() && (accessible->parent()->role() == QAccessible::Application); + bool topLevelWindow = accessible->parent() && (accessible->parent()->role() == QAccessible::Application); switch (idProp) { case UIA_ProcessIdPropertyId: @@ -379,7 +384,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantString(QStringLiteral("Qt"), pRetVal); break; case UIA_ControlTypePropertyId: - if (clientTopLevel) { + if (topLevelWindow) { // Reports a top-level widget as a window, instead of "custom". setVariantI4(UIA_WindowControlTypeId, pRetVal); } else { @@ -391,10 +396,20 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR setVariantString(accessible->text(QAccessible::Help), pRetVal); break; case UIA_HasKeyboardFocusPropertyId: - setVariantBool(accessible->state().focused, pRetVal); + if (topLevelWindow) { + // Windows set the active state to true when they are focused + setVariantBool(accessible->state().active, pRetVal); + } else { + setVariantBool(accessible->state().focused, pRetVal); + } break; case UIA_IsKeyboardFocusablePropertyId: - setVariantBool(accessible->state().focusable, pRetVal); + if (topLevelWindow) { + // Windows should always be focusable + setVariantBool(true, pRetVal); + } else { + setVariantBool(accessible->state().focusable, pRetVal); + } break; case UIA_IsOffscreenPropertyId: setVariantBool(accessible->state().offscreen, pRetVal); @@ -424,7 +439,7 @@ HRESULT QWindowsUiaMainProvider::GetPropertyValue(PROPERTYID idProp, VARIANT *pR break; case UIA_NamePropertyId: { QString name = accessible->text(QAccessible::Name); - if (name.isEmpty() && clientTopLevel) + if (name.isEmpty() && topLevelWindow) name = QCoreApplication::applicationName(); setVariantString(name, pRetVal); break; diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp new file mode 100644 index 0000000000..3738aa72ff --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.cpp @@ -0,0 +1,168 @@ +/**************************************************************************** +** +** 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwindowsuiawindowprovider.h" +#include "qwindowsuiautils.h" +#include "qwindowscontext.h" + +#include <QtGui/qaccessible.h> +#include <QtGui/private/qwindow_p.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +using namespace QWindowsUiAutomation; + + +QWindowsUiaWindowProvider::QWindowsUiaWindowProvider(QAccessible::Id id) : + QWindowsUiaBaseProvider(id) +{ +} + +QWindowsUiaWindowProvider::~QWindowsUiaWindowProvider() +{ +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::SetVisualState(WindowVisualState state) { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + auto window = accessible->window(); + switch (state) { + case WindowVisualState_Normal: + window->showNormal(); + break; + case WindowVisualState_Maximized: + window->showMaximized(); + break; + case WindowVisualState_Minimized: + window->showMinimized(); + break; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::Close() { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + accessible->window()->close(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) { + Q_UNUSED(milliseconds); + Q_UNUSED(pRetVal); + return UIA_E_NOTSUPPORTED; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_CanMaximize(__RPC__out BOOL *pRetVal) { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + + auto window = accessible->window(); + auto flags = window->flags(); + + *pRetVal = (!(flags & Qt::MSWindowsFixedSizeDialogHint) + && (flags & Qt::WindowMaximizeButtonHint) + && ((flags & Qt::CustomizeWindowHint) + || window->maximumSize() == QSize(QWINDOWSIZE_MAX, QWINDOWSIZE_MAX))); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_CanMinimize(__RPC__out BOOL *pRetVal) { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + *pRetVal = accessible->window()->flags() & Qt::WindowMinimizeButtonHint; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_IsModal(__RPC__out BOOL *pRetVal) { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + *pRetVal = accessible->window()->isModal(); + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_WindowVisualState(__RPC__out enum WindowVisualState *pRetVal) { + qCDebug(lcQpaUiAutomation) << __FUNCTION__; + QAccessibleInterface *accessible = accessibleInterface(); + if (!accessible || !accessible->window()) + return UIA_E_ELEMENTNOTAVAILABLE; + auto visibility = accessible->window()->visibility(); + switch (visibility) { + case QWindow::FullScreen: + case QWindow::Maximized: + *pRetVal = WindowVisualState_Maximized; + break; + case QWindow::Minimized: + *pRetVal = WindowVisualState_Minimized; + break; + default: + *pRetVal = WindowVisualState_Normal; + break; + } + return S_OK; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_WindowInteractionState(__RPC__out enum WindowInteractionState *pRetVal) { + Q_UNUSED(pRetVal); + return UIA_E_NOTSUPPORTED; +} + +HRESULT STDMETHODCALLTYPE QWindowsUiaWindowProvider::get_IsTopmost(__RPC__out BOOL *pRetVal) { + Q_UNUSED(pRetVal); + return UIA_E_NOTSUPPORTED; +} + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) diff --git a/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h new file mode 100644 index 0000000000..343fb275f7 --- /dev/null +++ b/src/plugins/platforms/windows/uiautomation/qwindowsuiawindowprovider.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** 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:LGPL$ +** 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 Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or 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.GPL2 and 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-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSUIAWINDOWPROVIDER_H +#define QWINDOWSUIAWINDOWPROVIDER_H + +#include <QtGui/qtguiglobal.h> +#if QT_CONFIG(accessibility) + +#include "qwindowsuiabaseprovider.h" + +QT_BEGIN_NAMESPACE + +class QWindowsUiaWindowProvider : public QWindowsUiaBaseProvider, + public QWindowsComBase<IWindowProvider> +{ + Q_DISABLE_COPY(QWindowsUiaWindowProvider) +public: + explicit QWindowsUiaWindowProvider(QAccessible::Id id); + ~QWindowsUiaWindowProvider() override; + + HRESULT STDMETHODCALLTYPE SetVisualState(WindowVisualState state) override; + HRESULT STDMETHODCALLTYPE Close( void) override; + HRESULT STDMETHODCALLTYPE WaitForInputIdle(int milliseconds, __RPC__out BOOL *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_CanMaximize(__RPC__out BOOL *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_CanMinimize(__RPC__out BOOL *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_IsModal(__RPC__out BOOL *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_WindowVisualState(__RPC__out WindowVisualState *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_WindowInteractionState(__RPC__out WindowInteractionState *pRetVal) override; + HRESULT STDMETHODCALLTYPE get_IsTopmost(__RPC__out BOOL *pRetVal) override; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(accessibility) + +#endif // QWINDOWSUIAWINDOWPROVIDER_H diff --git a/src/plugins/platforms/windows/uiautomation/uiautomation.pri b/src/plugins/platforms/windows/uiautomation/uiautomation.pri index e3071766d9..5d4fa5755b 100644 --- a/src/plugins/platforms/windows/uiautomation/uiautomation.pri +++ b/src/plugins/platforms/windows/uiautomation/uiautomation.pri @@ -18,6 +18,7 @@ SOURCES += \ $$PWD/qwindowsuiatableitemprovider.cpp \ $$PWD/qwindowsuiagridprovider.cpp \ $$PWD/qwindowsuiagriditemprovider.cpp \ + $$PWD/qwindowsuiawindowprovider.cpp \ $$PWD/qwindowsuiautils.cpp HEADERS += \ @@ -37,6 +38,7 @@ HEADERS += \ $$PWD/qwindowsuiatableitemprovider.h \ $$PWD/qwindowsuiagridprovider.h \ $$PWD/qwindowsuiagriditemprovider.h \ + $$PWD/qwindowsuiawindowprovider.h \ $$PWD/qwindowsuiautils.h mingw: LIBS *= -luuid diff --git a/src/plugins/platforms/xcb/qxcbdrag.cpp b/src/plugins/platforms/xcb/qxcbdrag.cpp index aa329d8cb7..1ce947165d 100644 --- a/src/plugins/platforms/xcb/qxcbdrag.cpp +++ b/src/plugins/platforms/xcb/qxcbdrag.cpp @@ -202,7 +202,7 @@ void QXcbDrag::startDrag() if (connection()->mouseGrabber() == nullptr) shapedPixmapWindow()->setMouseGrabEnabled(true); - auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow); + auto nativePixelPos = QHighDpi::toNativePixels(QCursor::pos(), initiatorWindow.data()); move(nativePixelPos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers()); } diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index c0bacd553d..8a1bd1431e 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -1859,6 +1859,9 @@ void QColorDialogPrivate::_q_addCustom() void QColorDialogPrivate::retranslateStrings() { + if (nativeDialogInUse) + return; + if (!smallDisplay) { lblBasicColors->setText(QColorDialog::tr("&Basic colors")); lblCustomColors->setText(QColorDialog::tr("&Custom colors")); diff --git a/src/widgets/doc/snippets/cmake-macros/examples.cmake b/src/widgets/doc/snippets/cmake-macros/examples.cmake new file mode 100644 index 0000000000..61ec7aed54 --- /dev/null +++ b/src/widgets/doc/snippets/cmake-macros/examples.cmake @@ -0,0 +1,5 @@ +#! [qt5_wrap_ui] +set(SOURCES mainwindow.cpp main.cpp) +qt5_wrap_ui(SOURCES mainwindow.ui) +add_executable(myapp ${SOURCES}) +#! [qt5_wrap_ui] diff --git a/src/widgets/doc/src/cmake-macros.qdoc b/src/widgets/doc/src/cmake-macros.qdoc new file mode 100644 index 0000000000..36579576a9 --- /dev/null +++ b/src/widgets/doc/src/cmake-macros.qdoc @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! +\page qtwidgets-cmake-qt5-wrap-ui.html +\ingroup cmake-macros-qtwidgets + +\title qt5_wrap_ui + +\brief Creates sources for \c{.ui} files. + +\section1 Synopsis + +\badcode +qt5_wrap_ui(<VAR> ui_file1 [ui_file2 ...] + [OPTIONS ...]) +\endcode + +\section1 Description + +Creates rules for calling \l{uic}{User Interface Compiler (uic)} on the given +\c{.ui} files. For each input file, an header file is generated in the build +directory. The paths of the generated header files are added to\c{<VAR>}. + +\note This is a low-level macro. See the \l{CMake AUTOUIC Documentation} for a +more convenient way to process \c{.ui} files with \c{uic}. + +\section1 Options + +You can set additional \c{OPTIONS} that should be added to the \c{uic} calls. +You can find possible options in the \l{uic}{uic documentation}. + +\section1 Examples + +\snippet cmake-macros/examples.cmake qt5_wrap_ui +*/ diff --git a/src/widgets/graphicsview/qgraphicsitem.cpp b/src/widgets/graphicsview/qgraphicsitem.cpp index 713f022bdd..65708fa1ca 100644 --- a/src/widgets/graphicsview/qgraphicsitem.cpp +++ b/src/widgets/graphicsview/qgraphicsitem.cpp @@ -9795,9 +9795,9 @@ QRectF QGraphicsPixmapItem::boundingRect() const return QRectF(); if (d->flags & ItemIsSelectable) { qreal pw = 1.0; - return QRectF(d->offset, d->pixmap.size() / d->pixmap.devicePixelRatio()).adjusted(-pw/2, -pw/2, pw/2, pw/2); + return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio()).adjusted(-pw/2, -pw/2, pw/2, pw/2); } else { - return QRectF(d->offset, d->pixmap.size() / d->pixmap.devicePixelRatio()); + return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio()); } } diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp index d863ef625b..0682717f54 100644 --- a/src/widgets/kernel/qwidget.cpp +++ b/src/widgets/kernel/qwidget.cpp @@ -2583,14 +2583,15 @@ void QWidgetPrivate::createWinId() /*! \internal Ensures that the widget is set on the screen point is on. This is handy getting a correct -size hint before a resize in e.g QMenu and QToolTip +size hint before a resize in e.g QMenu and QToolTip. +Returns if the screen was changed. */ -void QWidgetPrivate::setScreenForPoint(const QPoint &pos) +bool QWidgetPrivate::setScreenForPoint(const QPoint &pos) { Q_Q(QWidget); if (!q->isWindow()) - return; + return false; // Find the screen for pos and make the widget undertand it is on that screen. const QScreen *currentScreen = windowHandle() ? windowHandle()->screen() : nullptr; QScreen *actualScreen = QGuiApplication::screenAt(pos); @@ -2599,7 +2600,9 @@ void QWidgetPrivate::setScreenForPoint(const QPoint &pos) createWinId(); if (windowHandle()) windowHandle()->setScreen(actualScreen); + return true; } + return false; } /*! diff --git a/src/widgets/kernel/qwidget_p.h b/src/widgets/kernel/qwidget_p.h index 797963b931..af4ad31501 100644 --- a/src/widgets/kernel/qwidget_p.h +++ b/src/widgets/kernel/qwidget_p.h @@ -355,7 +355,7 @@ public: void createRecursively(); void createWinId(); - void setScreenForPoint(const QPoint &pos); + bool setScreenForPoint(const QPoint &pos); void createTLExtra(); void createExtra(); diff --git a/src/widgets/util/qcompleter.cpp b/src/widgets/util/qcompleter.cpp index 0daa4a4b41..e41f7e7573 100644 --- a/src/widgets/util/qcompleter.cpp +++ b/src/widgets/util/qcompleter.cpp @@ -976,18 +976,48 @@ void QCompleterPrivate::showPopup(const QRect& rect) popup->show(); } +#if QT_CONFIG(filesystemmodel) +static bool isRoot(const QFileSystemModel *model, const QString &path) +{ + const auto index = model->index(path); + return index.isValid() && model->fileInfo(index).isRoot(); +} + +static bool completeOnLoaded(const QFileSystemModel *model, + const QString &nativePrefix, + const QString &path, + Qt::CaseSensitivity caseSensitivity) +{ + const auto pathSize = path.size(); + const auto prefixSize = nativePrefix.size(); + if (prefixSize < pathSize) + return false; + const QString prefix = QDir::fromNativeSeparators(nativePrefix); + if (prefixSize == pathSize) + return path.compare(prefix, caseSensitivity) == 0 && isRoot(model, path); + // The user is typing something within that directory and is not in a subdirectory yet. + const auto separator = QLatin1Char('/'); + return prefix.startsWith(path, caseSensitivity) && prefix.at(pathSize) == separator + && !prefix.rightRef(prefixSize - pathSize - 1).contains(separator); +} + void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &path) { Q_Q(QCompleter); // Slot called when QFileSystemModel has finished loading. // If we hide the popup because there was no match because the model was not loaded yet, - // we re-start the completion when we get the results - if (hiddenBecauseNoMatch - && prefix.startsWith(path) && prefix != (path + QLatin1Char('/')) - && widget) { - q->complete(); + // we re-start the completion when we get the results (unless triggered by + // something else, see QTBUG-14292). + if (hiddenBecauseNoMatch && widget) { + if (auto model = qobject_cast<const QFileSystemModel *>(proxy->sourceModel())) { + if (completeOnLoaded(model, prefix, path, cs)) + q->complete(); + } } } +#else // QT_CONFIG(filesystemmodel) +void QCompleterPrivate::_q_fileSystemModelDirectoryLoaded(const QString &) {} +#endif /*! Constructs a completer object with the given \a parent. diff --git a/src/widgets/widgets/qmenu.cpp b/src/widgets/widgets/qmenu.cpp index 14964a696d..287be3e272 100644 --- a/src/widgets/widgets/qmenu.cpp +++ b/src/widgets/widgets/qmenu.cpp @@ -73,6 +73,7 @@ #endif #include "qpushbutton.h" #include "qtooltip.h" +#include <qwindow.h> #include <private/qpushbutton_p.h> #include <private/qaction_p.h> #include <private/qguiapplication_p.h> @@ -1485,6 +1486,8 @@ void QMenuPrivate::_q_platformMenuAboutToShow() { Q_Q(QMenu); + emit q->aboutToShow(); + #ifdef Q_OS_OSX if (platformMenu) { const auto actions = q->actions(); @@ -1498,8 +1501,6 @@ void QMenuPrivate::_q_platformMenuAboutToShow() } } #endif - - emit q->aboutToShow(); } bool QMenuPrivate::hasMouseMoved(const QPoint &globalPos) @@ -2328,8 +2329,10 @@ void QMenu::popup(const QPoint &p, QAction *atAction) d->motions = 0; d->doChildEffects = true; d->updateLayoutDirection(); - // Ensure that we get correct sizeHints by placing this window on the right screen. - d->setScreenForPoint(p); + + // Ensure that we get correct sizeHints by placing this window on the correct screen. + if (d->setScreenForPoint(p)) + d->itemsDirty = true; const bool contextMenu = d->isContextMenu(); if (d->lastContextMenu != contextMenu) { diff --git a/src/widgets/widgets/qwidgetresizehandler.cpp b/src/widgets/widgets/qwidgetresizehandler.cpp index 7ed6f6d78d..e8d435429f 100644 --- a/src/widgets/widgets/qwidgetresizehandler.cpp +++ b/src/widgets/widgets/qwidgetresizehandler.cpp @@ -121,7 +121,7 @@ bool QWidgetResizeHandler::eventFilter(QObject *o, QEvent *ee) break; const QRect widgetRect = widget->rect().marginsAdded(QMargins(range, range, range, range)); const QPoint cursorPoint = widget->mapFromGlobal(e->globalPos()); - if (!widgetRect.contains(cursorPoint) || mode == Nowhere) + if (!widgetRect.contains(cursorPoint)) return false; if (e->button() == Qt::LeftButton) { #if 0 // Used to be included in Qt4 for Q_WS_X11 diff --git a/src/winmain/qtmain_winrt.cpp b/src/winmain/qtmain_winrt.cpp index 7cc57f4d46..1828c4ca16 100644 --- a/src/winmain/qtmain_winrt.cpp +++ b/src/winmain/qtmain_winrt.cpp @@ -317,23 +317,26 @@ private: if (quote) break; commandLine[i] = '\0'; - if (args.last()[0] != '\0') + if (!args.isEmpty() && args.last() && args.last()[0] != '\0') args.append(commandLine.data() + i + 1); // fall through default: - if (args.last()[0] == '\0') + if (!args.isEmpty() && args.last() && args.last()[0] == '\0') args.last() = commandLine.data() + i; escape = false; // only quotes are escaped break; } } - if (args.count() >= 2 && strncmp(args.at(1), "-ServerName:", 12) == 0) + if (args.count() >= 2 && args.at(1) && strncmp(args.at(1), "-ServerName:", 12) == 0) args.remove(1); bool develMode = false; bool debugWait = false; for (int i = args.count() - 1; i >= 0; --i) { + if (!args.at(i)) + continue; + const char *arg = args.at(i); if (strcmp(arg, "-qdevel") == 0) { develMode = true; diff --git a/src/xml/doc/src/qtxml-index.qdoc b/src/xml/doc/src/qtxml-index.qdoc index dfb9b45fa7..65c6673db0 100644 --- a/src/xml/doc/src/qtxml-index.qdoc +++ b/src/xml/doc/src/qtxml-index.qdoc @@ -30,8 +30,10 @@ \title Qt XML \brief The Qt XML module provides C++ implementations of the SAX and DOM standards for XML. - The module is not actively maintained anymore. Please use - the QXmlStreamReader and QXmlStreamWriter classes in Qt Core instead. + Note that the module will not receive additional features anymore. For reading or writing XML + documents iteratively (SAX), we recommend using Qt Core's QXmlStreamReader and + QXmlStreamWriter classes. The classes are both easier to use and more compliant with the + XML standard. To include the definitions of the module's classes, use the following directive: diff --git a/src/xml/doc/src/qtxml.qdoc b/src/xml/doc/src/qtxml.qdoc index ad9b08b623..452e39d745 100644 --- a/src/xml/doc/src/qtxml.qdoc +++ b/src/xml/doc/src/qtxml.qdoc @@ -33,8 +33,10 @@ \brief The Qt XML module provides C++ implementations of the SAX and DOM standards for XML. - The module is not actively maintained anymore. Please use - the \l{QXmlStreamReader} and \l{QXmlStreamWriter} classes in \l{Qt Core} instead. + Note that the module will not receive additional features anymore. For reading or writing XML + documents iteratively (SAX), we recommend using Qt Core's QXmlStreamReader and + QXmlStreamWriter classes. The classes are both easier to use and more compliant with the + XML standard. To include the definitions of the module's classes, use the following directive: |