Merge remote-tracking branch 'origin/5.10' into dev

Conflicts:
	src/plugins/platforms/windows/qwindowsmousehandler.cpp
	src/plugins/platforms/xcb/qxcbimage.cpp
	tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
	tests/manual/qtabletevent/regular_widgets/main.cpp

Done-with: Friedemann Kleint<Friedemann.Kleint@qt.io>
Done-with: Mårten Nordheim<marten.nordheim@qt.io>
Change-Id: I5b2499513a92c590ed0756f7d2e93c35a64b7f30
This commit is contained in:
Allan Sandfeld Jensen 2017-10-24 10:37:17 +02:00 committed by Liang Qi
commit fa9d12f4a2
141 changed files with 1586 additions and 891 deletions

1
.gitignore vendored
View File

@ -28,6 +28,7 @@
/src/corelib/global/qconfig_p.h /src/corelib/global/qconfig_p.h
/bin/qt.conf /bin/qt.conf
/bin/qmake /bin/qmake
/bin/qvkgen
/qmake/qmake /qmake/qmake
qt*-config.h qt*-config.h
qt*-config_p.h qt*-config_p.h

259
dist/changes-5.9.2 vendored Normal file
View File

@ -0,0 +1,259 @@
Qt 5.9.2 is a bug-fix release. It maintains both forward and backward
compatibility (source and binary) with Qt 5.9.0.
For more details, refer to the online documentation included in this
distribution. The documentation is also available online:
http://doc.qt.io/qt-5/index.html
The Qt version 5.9 series is binary compatible with the 5.8.x series.
Applications compiled for 5.8 will continue to run with 5.9.
Some of the changes listed in this file include issue tracking numbers
corresponding to tasks in the Qt Bug Tracker:
https://bugreports.qt.io/
Each of these identifiers can be entered in the bug tracker to obtain more
information about a particular change.
****************************************************************************
* Important Behavior Changes *
****************************************************************************
- Building examples inside the Qt source tree while not building Qt itself
is rejected now, because this can cause hard to debug configuration
issues. If building isolated examples is needed, you may still use shadow
builds.
- This version of Qt restores compatibility with pre-5.9.0 calculation of
QCryptographicHash algorithms that were labelled "Sha3_nnn": that is,
applications compiled with old versions of Qt will continue using the
Keccak algorithm. Applications recompiled with this version will use
SHA-3, unless QT_SHA3_KECCAK_COMPAT is #define'd prior to #include
<QCryptographicHash>.
****************************************************************************
* General Notes *
****************************************************************************
Binary Compatibility Note
-------------------------
- The variable QOperatingSystemVersion::AndroidOreo was added in this
release. Code that uses this variable will not run under Qt 5.9.1. If
backwards compatibility is desired, use instead
QOperatingSystemVersion(QOperatingSystemVersion::Android, 8)
[This is similar to QOperatingSystemVersion::MacOSHighSierra added in
5.9.1]
- This version of Qt changes the values assigned to enumerations
QCryptographicHash::Sha3_nnn. Applications compiled with this version and
using those enumerations will not work with Qt 5.9.0 and 5.9.1, unless
QT_SHA3_KECCAK_COMPAT is defined.
Deprecation Notice
------------------
- Starting with Qt 5.10, IPv6 support will be mandatory for all platforms.
Systems without proper IPv6 support, such as the getaddrinfo() function
or the proper socket address structures, will not be able to build
QtNetwork anymore.
Third-Party Code
----------------
- [QTBUG-31020] zlib was updated to version 1.2.11.
- libpng was updated to version 1.6.32
****************************************************************************
* Library *
****************************************************************************
QtCore
------
- [QTBUG-61350] Fixed the conversion from string to double of the strings
"0E+1" and "0E-1" (with capital E), which QString::toDouble(),
QByteArray::toDouble() and similar functions reported as invalid.
- QFile:
* [QTBUG-57023] Reverted an incorrect change from Qt 5.9.0 that forbade
the creation and access to Alternate Data Streams on NTFS on Windows.
This means that file names containing a colon (':') are allowed again,
but note that they are not regular files.
- QFileInfo:
* [QTBUG-62802] Relative symbolic links on Windows are now resolved to
their absolute path by symLinkTarget().
- QFileSystemWatcher:
* [QTBUG-62242] Fixed a crash on Windows if this class was instantiated
before QCoreApplication was created.
* [QTBUG-61792] Fixed an issue on Windows that would cause this class not
to monitor files properly if the directory containing the monitored
files was added to the list of watched paths after the files.
- QLocale:
* [QTBUG-53565] Fixed the conversion of QTime to string form and parsing
from string form to always treat the value as the decimal fraction of
the seconds component. That is, the string format ".z" produces/parses
".2" for 200 milliseconds and ".002" for 2 milliseconds. Use of "z" or
"zzz" is discouraged outside decimal fractions to avoid surprises.
* [QTBUG-61949] Fixed bcp57Name() to return "en" for the QLocale::c()
locale. Previously, it returned "C", which is not a valid BCP47
language tag.
- QProcess:
* [QTBUG-61634] Added a workaround for a rare race-condition bug in
some C libraries that caused the child process started by QProcess to
hang after trying to launch a non-existent executable or change to a
non-existent directory.
* [QTBUG-62584] Fixed a race-condition bug that could cause
waitForXxx() functions to hang forever if a slot triggered by that
function futher started a nested event loop.
- QTimeZone:
* [QTBUG-63205] Fixed a bug that would cause QTimeZone to mis-parse
timezone files on Unix systems if they contained leap second
information.
- QVariant:
* [QTBUG-61471] Fixed QVariant to actually perform the conversions
between QVariantHash and QVariantMap in the respective .toHash() and
.toMap() functions. QVariant already reported true in .canConvert()
between those two types.
QtDBus
------
- [QTBUG-62284] Fixed a race condition in QDBusAbstractInterface that
could cause the class to never see the notification that the remote
service became available and cause isValid() to change to true.
QtGui
-----
- Text:
* [QTBUG-61520] Fixed matching of non-regular font weights for
application fonts on macOS.
QtNetwork
---------
- [QTBUG-61692] Fixed the handling of application-wide proxy settings (set
with QNetworkProxy): previously, QTcpSocket would directly fall back to
the system settings if the object-specific setting was
QNetworkProxy::DefaultProxy.
- QLocalSocket:
* [QTBUG-61643] Fixed an issue with Qt pipe-handling code that could
cause deadlocks on Windows, most often if the QLocalSocket object tried
to wait for more data during application shutdown.
QtTest
------
- Added flowId to messages when logging in TeamCity format. FlowId is used
to distinguish logging from multiple processes running in parallel.
QtWidgets
---------
- Android:
* [QTBUG-48639] Fixed label duplication for buttons when using style
sheets with the Android style.
- QLineEdit:
* [QTBUG-60319] Fixed behavior of the ImSurroundingText query.
Previously, it returned a masked text whose length may be less than
the cursor position. Now it returns unmasked text, so the text length
is always greater than or equal to the cursor position.
- QMenu:
* [QTBUG-59794] Fixed menu size issue when using high DPI on
multi-screen system.
****************************************************************************
* Compiler-specific Changes *
****************************************************************************
clang
-----
- [QTBUG-61840][QTBUG-62085] Fixed an issue that caused recent Clang
versions to print a warning about [[nodiscard].
Visual Studio
-------------
- [QTBUG-61902] Changed Qt uses of certain C++ Standard Library functions
that Visual Studio warns about. Now Qt public headers call
Microsoft-specific versions that do not produce warnings.
****************************************************************************
* Platform-specific Changes *
****************************************************************************
macOS
-----
- [QTBUG-59222] Switching focus objects inside a top level window while
composing text using dead keys or input method events would leave the
application in an inconsistent state. The composition now automatically
cancels when the focus object changes.
Windows
-------
- [QTBUG-57916] Fixed build with ANGLE and newer MinGW versions.
- [QTBUG-62083] Fixed Qt trying to steal certain events from user windows if
the event ID was WM_USER.
****************************************************************************
* Tools *
****************************************************************************
configure & build system
------------------------
- [QTBUG-35928][QTBUG-41908][Apple] Qt can now be built using just the
Xcode Command Line Tools, without needing to install the full Xcode IDE.
- [QTBUG-55755][Windows] All Qt .exe files now include meta information,
like .dll files already did.
- [QTBUG-58012] (Re-)added a way to specify alternative ICU libraries.
- [QTBUG-62150] Fixed detection of ICU in static builds.
- [QTBUG-53537][X11] Added missing detection of Xinerama.
- [QTBUG-61731][X11] Fixed detection of AT-SPI, allowing accessibility
support to be built again.
- [X11] Fixed detection of x11-xcb with pkg-config.
- [CMake] All Qt module defines are now propagated to the config files.
qmake
-----
- [QTBUG-31034] Added qmake feature and configure option to use ccache.
- [QTBUG-48342] Fixed generation of extraneous slashes in -project mode.
- [QTBUG-55633] Fixed misparsing of some string literal concatenations
as C++11 raw strings. This affects dependency scanning.
- [QTBUG-59301][Xcode] Fixed duplicate references in project files.
- [QTBUG-59827][nmake] The 'clean' target now deletes backup files of
MSVC manifests.
- [QTBUG-60455][Android] libc++ is now used instead of libstdc++ when
building with the android-clang mkspec.
- [QTBUG-60430][iOS] Fixed handling of the deprecated variable
QMAKE_IOS_TARGETED_DEVICE_FAMILY.
- [QTBUG-60899][WinRT] Fixed capability handling for Win10 targets.
- [WinRT] Added support for new Win10 capabilities.
- [QTBUG-61335][MinGW] Worked around LTO+MRI linker issue when cross-
building from Linux.
- [QTBUG-61411][Windows] _UNICODE is now defined, consistently with VS.
- [QTBUG-61688][MSVC] Fixed compilation of precompiled headers with
CONFIG+=silent. Done by removing redundant progress messages.
- [QTBUG-61690][QTBUG-61735] Fixed detection of compiler default search
paths for various compilers and platforms.
- [QTBUG-63197][Windows] Fixed moc'ing in a build directory with spaces
when INCLUDEPATH contains 40+ entries.
- [Android] Fixed building with ndkr16+ by using unified headers.
- [Windows] Fixed repeated installation of read-only files.
- [VS] Fixed deployment rules in created solution files.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 39 KiB

View File

@ -60,8 +60,8 @@
the address book. the address book.
\c TableModel is a subclass of QAbstractTableModel that provides \c TableModel is a subclass of QAbstractTableModel that provides
the standard model/view API to access data. It also holds a the standard model/view API to access data. It holds a list of
QList of \l{QPair}s corresponding to the contacts added. added contacts.
However, this data is not all visible in a single tab. Instead, However, this data is not all visible in a single tab. Instead,
QTableView is used to provide 9 different views of the same QTableView is used to provide 9 different views of the same
data, according to the alphabet groups. data, according to the alphabet groups.
@ -80,7 +80,7 @@
\section1 TableModel Class Definition \section1 TableModel Class Definition
The \c TableModel class provides standard API to access data in The \c TableModel class provides standard API to access data in
its QList of \l{QPair}s by subclassing QAbstractTableModel. The its list of contacts by subclassing QAbstractTableModel. The
basic functions that must be implemented in order to do so are: basic functions that must be implemented in order to do so are:
\c rowCount(), \c columnCount(), \c data(), \c headerData(). \c rowCount(), \c columnCount(), \c data(), \c headerData().
For TableModel to be editable, it has to provide implementations For TableModel to be editable, it has to provide implementations
@ -90,15 +90,14 @@
\snippet itemviews/addressbook/tablemodel.h 0 \snippet itemviews/addressbook/tablemodel.h 0
Two constructors are used, a default constructor which uses Two constructors are used, a default constructor which uses
\c TableModel's own \c {QList<QPair<QString, QString>>} and one \c TableModel's own \c {QList<Contact>} and one that takes
that takes \c {QList<QPair<QString, QString>} as an argument, \c {QList<Contact>} as an argument, for convenience.
for convenience.
\section1 TableModel Class Implementation \section1 TableModel Class Implementation
We implement the two constructors as defined in the header file. We implement the two constructors as defined in the header file.
The second constructor initializes the list of pairs in the The second constructor initializes the list of contacts in the
model, with the parameter value. model, with the parameter value.
\snippet itemviews/addressbook/tablemodel.cpp 0 \snippet itemviews/addressbook/tablemodel.cpp 0
@ -117,7 +116,7 @@
The \c data() function returns either a \b Name or The \c data() function returns either a \b Name or
\b {Address}, based on the contents of the model index \b {Address}, based on the contents of the model index
supplied. The row number stored in the model index is used to supplied. The row number stored in the model index is used to
reference an item in the list of pairs. Selection is handled reference an item in the list of contacts. Selection is handled
by the QItemSelectionModel, which will be explained with by the QItemSelectionModel, which will be explained with
\c AddressWidget. \c AddressWidget.
@ -164,12 +163,11 @@
use the editing features of the QTableView object, we enable use the editing features of the QTableView object, we enable
them here so that we can reuse the model in other programs. them here so that we can reuse the model in other programs.
The last function in \c {TableModel}, \c getList() returns the The last function in \c {TableModel}, \c getContacts() returns the
QList<QPair<QString, QString>> object that holds all the QList<Contact> object that holds all the contacts in the address
contacts in the address book. We use this function later to book. We use this function later to obtain the list of contacts to
obtain the list of contacts to check for existing entries, write check for existing entries, write the contacts to a file and read
the contacts to a file and read them back. Further explanation is them back. Further explanation is given with \c AddressWidget.
given with \c AddressWidget.
\snippet itemviews/addressbook/tablemodel.cpp 8 \snippet itemviews/addressbook/tablemodel.cpp 8
@ -222,11 +220,12 @@
The QItemSelectionModel class provides a The QItemSelectionModel class provides a
\l{QItemSelectionModel::selectionChanged()}{selectionChanged} \l{QItemSelectionModel::selectionChanged()}{selectionChanged}
signal that is connected to \c{AddressWidget}'s signal that is connected to \c{AddressWidget}'s
\c selectionChanged() signal. This signal to signal connection \c selectionChanged() signal. We also connect
is necessary to enable the \uicontrol{Edit Entry...} and QTabWidget::currentChanged() signal to the lambda expression which
\uicontrol{Remove Entry} actions in \c MainWindow's Tools menu. This emits \c{AddressWidget}'s \c selectionChanged() as well. These
connection is further explained in \c MainWindow's connections are necessary to enable the \uicontrol{Edit Entry...} and
implementation. \uicontrol{Remove Entry} actions in \c MainWindow's Tools menu.
It is further explained in \c MainWindow's implementation.
Each table view in the address book is added as a tab to the Each table view in the address book is added as a tab to the
QTabWidget with the relevant label, obtained from the QStringList QTabWidget with the relevant label, obtained from the QStringList
@ -250,7 +249,7 @@
Basic validation is done in the second \c addEntry() function to Basic validation is done in the second \c addEntry() function to
prevent duplicate entries in the address book. As mentioned with prevent duplicate entries in the address book. As mentioned with
\c TableModel, this is part of the reason why we require the \c TableModel, this is part of the reason why we require the
getter method \c getList(). getter method \c getContacts().
\snippet itemviews/addressbook/addresswidget.cpp 3 \snippet itemviews/addressbook/addresswidget.cpp 3
@ -292,7 +291,7 @@
The \c writeToFile() function is used to save a file containing The \c writeToFile() function is used to save a file containing
all the contacts in the address book. The file is saved in a all the contacts in the address book. The file is saved in a
custom \c{.dat} format. The contents of the QList of \l{QPair}s custom \c{.dat} format. The contents of the list of contacts
are written to \c file using QDataStream. If the file cannot be are written to \c file using QDataStream. If the file cannot be
opened, a QMessageBox is displayed with the related error message. opened, a QMessageBox is displayed with the related error message.
@ -301,7 +300,7 @@
The \c readFromFile() function loads a file containing all the The \c readFromFile() function loads a file containing all the
contacts in the address book, previously saved using contacts in the address book, previously saved using
\c writeToFile(). QDataStream is used to read the contents of a \c writeToFile(). QDataStream is used to read the contents of a
\c{.dat} file into a list of pairs and each of these is added \c{.dat} file into a list of contacts and each of these is added
using \c addEntry(). using \c addEntry().
\snippet itemviews/addressbook/addresswidget.cpp 7 \snippet itemviews/addressbook/addresswidget.cpp 7

View File

@ -62,7 +62,7 @@ QT_END_NAMESPACE
class DragWidget : public QFrame class DragWidget : public QFrame
{ {
public: public:
DragWidget(QWidget *parent = 0); explicit DragWidget(QWidget *parent = nullptr);
protected: protected:
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;

View File

@ -123,7 +123,7 @@ void DragWidget::dropEvent(QDropEvent *event)
hotSpot.setY(hotSpotPos.last().toInt()); hotSpot.setY(hotSpotPos.last().toInt());
} }
foreach (const QString &piece, pieces) { for (const QString &piece : pieces) {
QLabel *newLabel = createDragLabel(piece, this); QLabel *newLabel = createDragLabel(piece, this);
newLabel->move(position - hotSpot); newLabel->move(position - hotSpot);
newLabel->show(); newLabel->show();
@ -141,7 +141,7 @@ void DragWidget::dropEvent(QDropEvent *event)
} else { } else {
event->ignore(); event->ignore();
} }
foreach (QWidget *widget, findChildren<QWidget *>()) { for (QWidget *widget : findChildren<QWidget *>()) {
if (!widget->isVisible()) if (!widget->isVisible())
widget->deleteLater(); widget->deleteLater();
} }

View File

@ -61,7 +61,7 @@ QT_END_NAMESPACE
class DragWidget : public QWidget class DragWidget : public QWidget
{ {
public: public:
DragWidget(QWidget *parent = 0); explicit DragWidget(QWidget *parent = nullptr);
protected: protected:
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;

View File

@ -63,13 +63,13 @@ class DropArea : public QLabel
Q_OBJECT Q_OBJECT
public: public:
DropArea(QWidget *parent = 0); explicit DropArea(QWidget *parent = nullptr);
public slots: public slots:
void clear(); void clear();
signals: signals:
void changed(const QMimeData *mimeData = 0); void changed(const QMimeData *mimeData = nullptr);
//! [DropArea header part1] //! [DropArea header part1]
//! [DropArea header part2] //! [DropArea header part2]

View File

@ -88,8 +88,8 @@ DropSiteWindow::DropSiteWindow()
buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole); buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole); buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
connect(quitButton, &QAbstractButton::pressed, this, &QWidget::close); connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
connect(clearButton, &QAbstractButton::pressed, dropArea, &DropArea::clear); connect(clearButton, &QAbstractButton::clicked, dropArea, &DropArea::clear);
//! [constructor part4] //! [constructor part4]
//! [constructor part5] //! [constructor part5]
@ -113,7 +113,7 @@ void DropSiteWindow::updateFormatsTable(const QMimeData *mimeData)
//! [updateFormatsTable() part1] //! [updateFormatsTable() part1]
//! [updateFormatsTable() part2] //! [updateFormatsTable() part2]
foreach (QString format, mimeData->formats()) { for (const QString &format : mimeData->formats()) {
QTableWidgetItem *formatItem = new QTableWidgetItem(format); QTableWidgetItem *formatItem = new QTableWidgetItem(format);
formatItem->setFlags(Qt::ItemIsEnabled); formatItem->setFlags(Qt::ItemIsEnabled);
formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft); formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft);

View File

@ -167,7 +167,7 @@ void DragWidget::dropEvent(QDropEvent *event)
QString::SkipEmptyParts); QString::SkipEmptyParts);
QPoint position = event->pos(); QPoint position = event->pos();
foreach (const QString &piece, pieces) { for (const QString &piece : pieces) {
DragLabel *newLabel = new DragLabel(piece, this); DragLabel *newLabel = new DragLabel(piece, this);
newLabel->move(position); newLabel->move(position);
newLabel->show(); newLabel->show();

View File

@ -62,7 +62,7 @@ QT_END_NAMESPACE
class DragWidget : public QWidget class DragWidget : public QWidget
{ {
public: public:
DragWidget(QWidget *parent = 0); explicit DragWidget(QWidget *parent = nullptr);
protected: protected:
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;

View File

@ -48,10 +48,10 @@
** **
****************************************************************************/ ****************************************************************************/
#include <QApplication>
#include "mainwindow.h" #include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
Q_INIT_RESOURCE(puzzle); Q_INIT_RESOURCE(puzzle);

View File

@ -67,12 +67,19 @@ MainWindow::MainWindow(QWidget *parent)
void MainWindow::openImage() void MainWindow::openImage()
{ {
const QString fileName = const QString directory =
QFileDialog::getOpenFileName(this, tr("Open Image"), QString(), QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
tr("Image Files (*.png *.jpg *.bmp)")); QFileDialog dialog(this, tr("Open Image"), directory);
dialog.setAcceptMode(QFileDialog::AcceptOpen);
if (!fileName.isEmpty()) dialog.setFileMode(QFileDialog::ExistingFile);
loadImage(fileName); QStringList mimeTypeFilters;
for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
mimeTypeFilters.append(mimeTypeName);
mimeTypeFilters.sort();
dialog.setMimeTypeFilters(mimeTypeFilters);
dialog.selectMimeTypeFilter("image/jpeg");
if (dialog.exec() == QDialog::Accepted)
loadImage(dialog.selectedFiles().constFirst());
} }
void MainWindow::loadImage(const QString &fileName) void MainWindow::loadImage(const QString &fileName)

View File

@ -51,8 +51,8 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QPixmap>
#include <QMainWindow> #include <QMainWindow>
#include <QPixmap>
class PiecesList; class PiecesList;
class PuzzleWidget; class PuzzleWidget;
@ -65,7 +65,7 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = nullptr);
void loadImage(const QString &path); void loadImage(const QString &path);
public slots: public slots:

View File

@ -101,7 +101,7 @@ void PiecesList::dropEvent(QDropEvent *event)
} }
} }
void PiecesList::addPiece(QPixmap pixmap, QPoint location) void PiecesList::addPiece(const QPixmap &pixmap, const QPoint &location)
{ {
QListWidgetItem *pieceItem = new QListWidgetItem(this); QListWidgetItem *pieceItem = new QListWidgetItem(this);
pieceItem->setIcon(QIcon(pixmap)); pieceItem->setIcon(QIcon(pixmap));

View File

@ -58,8 +58,8 @@ class PiecesList : public QListWidget
Q_OBJECT Q_OBJECT
public: public:
explicit PiecesList(int pieceSize, QWidget *parent = 0); explicit PiecesList(int pieceSize, QWidget *parent = nullptr);
void addPiece(QPixmap pixmap, QPoint location); void addPiece(const QPixmap &pixmap, const QPoint &location);
static QString puzzleMimeType() { return QStringLiteral("image/x-puzzle-piece"); } static QString puzzleMimeType() { return QStringLiteral("image/x-puzzle-piece"); }

View File

@ -66,9 +66,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
void PuzzleWidget::clear() void PuzzleWidget::clear()
{ {
pieceLocations.clear(); pieces.clear();
piecePixmaps.clear();
pieceRects.clear();
highlightedRect = QRect(); highlightedRect = QRect();
inPlace = 0; inPlace = 0;
update(); update();
@ -95,7 +93,7 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
QRect updateRect = highlightedRect.united(targetSquare(event->pos())); QRect updateRect = highlightedRect.united(targetSquare(event->pos()));
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()) if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
&& pieceRects.indexOf(targetSquare(event->pos())) == -1) { && findPiece(targetSquare(event->pos())) == -1) {
highlightedRect = targetSquare(event->pos()); highlightedRect = targetSquare(event->pos());
event->setDropAction(Qt::MoveAction); event->setDropAction(Qt::MoveAction);
@ -111,26 +109,23 @@ void PuzzleWidget::dragMoveEvent(QDragMoveEvent *event)
void PuzzleWidget::dropEvent(QDropEvent *event) void PuzzleWidget::dropEvent(QDropEvent *event)
{ {
if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType()) if (event->mimeData()->hasFormat(PiecesList::puzzleMimeType())
&& pieceRects.indexOf(targetSquare(event->pos())) == -1) { && findPiece(targetSquare(event->pos())) == -1) {
QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType()); QByteArray pieceData = event->mimeData()->data(PiecesList::puzzleMimeType());
QDataStream dataStream(&pieceData, QIODevice::ReadOnly); QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
QRect square = targetSquare(event->pos()); Piece piece;
QPixmap pixmap; piece.rect = targetSquare(event->pos());
QPoint location; dataStream >> piece.pixmap >> piece.location;
dataStream >> pixmap >> location;
pieceLocations.append(location); pieces.append(piece);
piecePixmaps.append(pixmap);
pieceRects.append(square);
highlightedRect = QRect(); highlightedRect = QRect();
update(square); update(piece.rect);
event->setDropAction(Qt::MoveAction); event->setDropAction(Qt::MoveAction);
event->accept(); event->accept();
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) { if (piece.location == piece.rect.topLeft() / pieceSize()) {
inPlace++; inPlace++;
if (inPlace == 25) if (inPlace == 25)
emit puzzleCompleted(); emit puzzleCompleted();
@ -141,21 +136,26 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
} }
} }
int PuzzleWidget::findPiece(const QRect &pieceRect) const
{
for (int i = 0, size = pieces.size(); i < size; ++i) {
if (pieces.at(i).rect == pieceRect)
return i;
}
return -1;
}
void PuzzleWidget::mousePressEvent(QMouseEvent *event) void PuzzleWidget::mousePressEvent(QMouseEvent *event)
{ {
QRect square = targetSquare(event->pos()); QRect square = targetSquare(event->pos());
int found = pieceRects.indexOf(square); const int found = findPiece(square);
if (found == -1) if (found == -1)
return; return;
QPoint location = pieceLocations[found]; Piece piece = pieces.takeAt(found);
QPixmap pixmap = piecePixmaps[found];
pieceLocations.removeAt(found);
piecePixmaps.removeAt(found);
pieceRects.removeAt(found);
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) if (piece.location == square.topLeft() / pieceSize())
inPlace--; inPlace--;
update(square); update(square);
@ -163,7 +163,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QByteArray itemData; QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly); QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << pixmap << location; dataStream << piece.pixmap << piece.location;
QMimeData *mimeData = new QMimeData; QMimeData *mimeData = new QMimeData;
mimeData->setData(PiecesList::puzzleMimeType(), itemData); mimeData->setData(PiecesList::puzzleMimeType(), itemData);
@ -171,23 +171,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QDrag *drag = new QDrag(this); QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData); drag->setMimeData(mimeData);
drag->setHotSpot(event->pos() - square.topLeft()); drag->setHotSpot(event->pos() - square.topLeft());
drag->setPixmap(pixmap); drag->setPixmap(piece.pixmap);
if (!(drag->exec(Qt::MoveAction) == Qt::MoveAction)) { if (drag->exec(Qt::MoveAction) != Qt::MoveAction) {
pieceLocations.insert(found, location); pieces.insert(found, piece);
piecePixmaps.insert(found, pixmap);
pieceRects.insert(found, square);
update(targetSquare(event->pos())); update(targetSquare(event->pos()));
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) if (piece.location == square.topLeft() / pieceSize())
inPlace++; inPlace++;
} }
} }
void PuzzleWidget::paintEvent(QPaintEvent *event) void PuzzleWidget::paintEvent(QPaintEvent *event)
{ {
QPainter painter; QPainter painter(this);
painter.begin(this);
painter.fillRect(event->rect(), Qt::white); painter.fillRect(event->rect(), Qt::white);
if (highlightedRect.isValid()) { if (highlightedRect.isValid()) {
@ -196,14 +193,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event)
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1)); painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
} }
for (int i = 0; i < pieceRects.size(); ++i) for (const Piece &piece : pieces)
painter.drawPixmap(pieceRects[i], piecePixmaps[i]); painter.drawPixmap(piece.rect, piece.pixmap);
painter.end();
} }
const QRect PuzzleWidget::targetSquare(const QPoint &position) const const QRect PuzzleWidget::targetSquare(const QPoint &position) const
{ {
return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize()); return QRect(position / pieceSize() * pieceSize(),
QSize(pieceSize(), pieceSize()));
} }
int PuzzleWidget::pieceSize() const int PuzzleWidget::pieceSize() const

View File

@ -51,9 +51,9 @@
#ifndef PUZZLEWIDGET_H #ifndef PUZZLEWIDGET_H
#define PUZZLEWIDGET_H #define PUZZLEWIDGET_H
#include <QList>
#include <QPoint> #include <QPoint>
#include <QPixmap> #include <QPixmap>
#include <QVector>
#include <QWidget> #include <QWidget>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit PuzzleWidget(int imageSize, QWidget *parent = 0); explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
void clear(); void clear();
int pieceSize() const; int pieceSize() const;
@ -85,11 +85,16 @@ protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
struct Piece {
QPixmap pixmap;
QRect rect;
QPoint location;
};
int findPiece(const QRect &pieceRect) const;
const QRect targetSquare(const QPoint &position) const; const QRect targetSquare(const QPoint &position) const;
QList<QPixmap> piecePixmaps; QVector<Piece> pieces;
QList<QRect> pieceRects;
QList<QPoint> pieceLocations;
QRect highlightedRect; QRect highlightedRect;
int inPlace; int inPlace;
int m_ImageSize; int m_ImageSize;

View File

@ -85,10 +85,7 @@ void AddressWidget::showAddEntryDialog()
//! [3] //! [3]
void AddressWidget::addEntry(QString name, QString address) void AddressWidget::addEntry(QString name, QString address)
{ {
QList<QPair<QString, QString> >list = table->getList(); if (!table->getContacts().contains({ name, address })) {
QPair<QString, QString> pair(name, address);
if (!list.contains(pair)) {
table->insertRows(0, 1, QModelIndex()); table->insertRows(0, 1, QModelIndex());
QModelIndex index = table->index(0, 0, QModelIndex()); QModelIndex index = table->index(0, 0, QModelIndex());
@ -195,6 +192,12 @@ void AddressWidget::setupTabs()
&QItemSelectionModel::selectionChanged, &QItemSelectionModel::selectionChanged,
this, &AddressWidget::selectionChanged); this, &AddressWidget::selectionChanged);
connect(this, &QTabWidget::currentChanged, this, [this](int tabIndex) {
auto *tableView = qobject_cast<QTableView *>(widget(tabIndex));
if (tableView)
emit selectionChanged(tableView->selectionModel()->selection());
});
addTab(tableView, str); addTab(tableView, str);
} }
} }
@ -211,18 +214,16 @@ void AddressWidget::readFromFile(const QString &fileName)
return; return;
} }
QList<QPair<QString, QString> > pairs = table->getList(); QList<Contact> contacts;
QDataStream in(&file); QDataStream in(&file);
in >> pairs; in >> contacts;
if (pairs.isEmpty()) { if (contacts.isEmpty()) {
QMessageBox::information(this, tr("No contacts in file"), QMessageBox::information(this, tr("No contacts in file"),
tr("The file you are attempting to open contains no contacts.")); tr("The file you are attempting to open contains no contacts."));
} else { } else {
for (int i=0; i<pairs.size(); ++i) { for (const auto &contact: qAsConst(contacts))
QPair<QString, QString> p = pairs.at(i); addEntry(contact.name, contact.address);
addEntry(p.first, p.second);
}
} }
} }
//! [7] //! [7]
@ -237,8 +238,7 @@ void AddressWidget::writeToFile(const QString &fileName)
return; return;
} }
QList<QPair<QString, QString> > pairs = table->getList();
QDataStream out(&file); QDataStream out(&file);
out << pairs; out << table->getContacts();
} }
//! [6] //! [6]

View File

@ -56,10 +56,10 @@ TableModel::TableModel(QObject *parent)
{ {
} }
TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent) TableModel::TableModel(QList<Contact> contacts, QObject *parent)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
, contacts(contacts)
{ {
listOfPairs = pairs;
} }
//! [0] //! [0]
@ -67,7 +67,7 @@ TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent)
int TableModel::rowCount(const QModelIndex &parent) const int TableModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
return listOfPairs.size(); return contacts.size();
} }
int TableModel::columnCount(const QModelIndex &parent) const int TableModel::columnCount(const QModelIndex &parent) const
@ -83,16 +83,16 @@ QVariant TableModel::data(const QModelIndex &index, int role) const
if (!index.isValid()) if (!index.isValid())
return QVariant(); return QVariant();
if (index.row() >= listOfPairs.size() || index.row() < 0) if (index.row() >= contacts.size() || index.row() < 0)
return QVariant(); return QVariant();
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
QPair<QString, QString> pair = listOfPairs.at(index.row()); const auto &contact = contacts.at(index.row());
if (index.column() == 0) if (index.column() == 0)
return pair.first; return contact.name;
else if (index.column() == 1) else if (index.column() == 1)
return pair.second; return contact.address;
} }
return QVariant(); return QVariant();
} }
@ -126,10 +126,8 @@ bool TableModel::insertRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index); Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + rows - 1); beginInsertRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) { for (int row = 0; row < rows; ++row)
QPair<QString, QString> pair(" ", " "); contacts.insert(position, { QString(), QString() });
listOfPairs.insert(position, pair);
}
endInsertRows(); endInsertRows();
return true; return true;
@ -142,9 +140,8 @@ bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index); Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1); beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) { for (int row = 0; row < rows; ++row)
listOfPairs.removeAt(position); contacts.removeAt(position);
}
endRemoveRows(); endRemoveRows();
return true; return true;
@ -157,16 +154,16 @@ bool TableModel::setData(const QModelIndex &index, const QVariant &value, int ro
if (index.isValid() && role == Qt::EditRole) { if (index.isValid() && role == Qt::EditRole) {
int row = index.row(); int row = index.row();
QPair<QString, QString> p = listOfPairs.value(row); auto contact = contacts.value(row);
if (index.column() == 0) if (index.column() == 0)
p.first = value.toString(); contact.name = value.toString();
else if (index.column() == 1) else if (index.column() == 1)
p.second = value.toString(); contact.address = value.toString();
else else
return false; return false;
listOfPairs.replace(row, p); contacts.replace(row, contact);
emit(dataChanged(index, index)); emit(dataChanged(index, index));
return true; return true;
@ -187,8 +184,8 @@ Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
//! [7] //! [7]
//! [8] //! [8]
QList< QPair<QString, QString> > TableModel::getList() QList<Contact> TableModel::getContacts() const
{ {
return listOfPairs; return contacts;
} }
//! [8] //! [8]

View File

@ -53,16 +53,37 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QList> #include <QList>
#include <QPair>
//! [0] //! [0]
struct Contact
{
QString name;
QString address;
bool operator==(const Contact &other) const
{
return name == other.name && address == other.address;
}
};
inline QDataStream &operator<<(QDataStream &stream, const Contact &contact)
{
return stream << contact.name << contact.address;
}
inline QDataStream &operator>>(QDataStream &stream, Contact &contact)
{
return stream >> contact.name >> contact.address;
}
class TableModel : public QAbstractTableModel class TableModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
TableModel(QObject *parent = 0); TableModel(QObject *parent = 0);
TableModel(QList<QPair<QString, QString> > listofPairs, QObject *parent = 0); TableModel(QList<Contact> contacts, QObject *parent = 0);
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override;
@ -72,10 +93,10 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
QList<QPair<QString, QString> > getList(); QList<Contact> getContacts() const;
private: private:
QList<QPair<QString, QString> > listOfPairs; QList<Contact> contacts;
}; };
//! [0] //! [0]

View File

@ -58,7 +58,7 @@ int main(int argc, char *argv[])
QApplication app(argc, argv); QApplication app(argc, argv);
MainWindow window; MainWindow window;
window.loadImage(":/images/example.jpg"); window.loadImage(QStringLiteral(":/images/example.jpg"));
window.show(); window.show();
return app.exec(); return app.exec();
} }

View File

@ -69,12 +69,19 @@ MainWindow::MainWindow(QWidget *parent)
void MainWindow::openImage() void MainWindow::openImage()
{ {
const QString fileName = const QString directory =
QFileDialog::getOpenFileName(this, QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).value(0, QDir::homePath());
tr("Open Image"), QString(), QFileDialog dialog(this, tr("Open Image"), directory);
tr("Image Files (*.png *.jpg *.bmp)")); dialog.setAcceptMode(QFileDialog::AcceptOpen);
if (!fileName.isEmpty()) dialog.setFileMode(QFileDialog::ExistingFile);
loadImage(fileName); QStringList mimeTypeFilters;
for (const QByteArray &mimeTypeName : QImageReader::supportedMimeTypes())
mimeTypeFilters.append(mimeTypeName);
mimeTypeFilters.sort();
dialog.setMimeTypeFilters(mimeTypeFilters);
dialog.selectMimeTypeFilter("image/jpeg");
if (dialog.exec() == QDialog::Accepted)
loadImage(dialog.selectedFiles().constFirst());
} }
void MainWindow::loadImage(const QString &fileName) void MainWindow::loadImage(const QString &fileName)
@ -83,7 +90,7 @@ void MainWindow::loadImage(const QString &fileName)
if (!newImage.load(fileName)) { if (!newImage.load(fileName)) {
QMessageBox::warning(this, tr("Open Image"), QMessageBox::warning(this, tr("Open Image"),
tr("The image file could not be loaded."), tr("The image file could not be loaded."),
QMessageBox::Cancel); QMessageBox::Close);
return; return;
} }
puzzleImage = newImage; puzzleImage = newImage;
@ -117,19 +124,15 @@ void MainWindow::setupMenus()
{ {
QMenu *fileMenu = menuBar()->addMenu(tr("&File")); QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
QAction *openAction = fileMenu->addAction(tr("&Open...")); QAction *openAction = fileMenu->addAction(tr("&Open..."), this, &MainWindow::openImage);
openAction->setShortcuts(QKeySequence::Open); openAction->setShortcuts(QKeySequence::Open);
QAction *exitAction = fileMenu->addAction(tr("E&xit")); QAction *exitAction = fileMenu->addAction(tr("E&xit"), qApp, &QCoreApplication::quit);
exitAction->setShortcuts(QKeySequence::Quit); exitAction->setShortcuts(QKeySequence::Quit);
QMenu *gameMenu = menuBar()->addMenu(tr("&Game")); QMenu *gameMenu = menuBar()->addMenu(tr("&Game"));
QAction *restartAction = gameMenu->addAction(tr("&Restart")); gameMenu->addAction(tr("&Restart"), this, &MainWindow::setupPuzzle);
connect(openAction, &QAction::triggered, this, &MainWindow::openImage);
connect(exitAction, &QAction::triggered, qApp, &QCoreApplication::quit);
connect(restartAction, &QAction::triggered, this, &MainWindow::setupPuzzle);
} }
void MainWindow::setupWidgets() void MainWindow::setupWidgets()

View File

@ -65,7 +65,7 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
MainWindow(QWidget *parent = 0); explicit MainWindow(QWidget *parent = nullptr);
public slots: public slots:
void openImage(); void openImage();

View File

@ -62,9 +62,7 @@ PuzzleWidget::PuzzleWidget(int imageSize, QWidget *parent)
void PuzzleWidget::clear() void PuzzleWidget::clear()
{ {
pieceLocations.clear(); pieces.clear();
piecePixmaps.clear();
pieceRects.clear();
highlightedRect = QRect(); highlightedRect = QRect();
inPlace = 0; inPlace = 0;
update(); update();
@ -110,23 +108,20 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
&& findPiece(targetSquare(event->pos())) == -1) { && findPiece(targetSquare(event->pos())) == -1) {
QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece"); QByteArray pieceData = event->mimeData()->data("image/x-puzzle-piece");
QDataStream stream(&pieceData, QIODevice::ReadOnly); QDataStream dataStream(&pieceData, QIODevice::ReadOnly);
QRect square = targetSquare(event->pos()); Piece piece;
QPixmap pixmap; piece.rect = targetSquare(event->pos());
QPoint location; dataStream >> piece.pixmap >> piece.location;
stream >> pixmap >> location;
pieceLocations.append(location); pieces.append(piece);
piecePixmaps.append(pixmap);
pieceRects.append(square);
highlightedRect = QRect(); highlightedRect = QRect();
update(square); update(piece.rect);
event->setDropAction(Qt::MoveAction); event->setDropAction(Qt::MoveAction);
event->accept(); event->accept();
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) { if (piece.location == piece.rect.topLeft() / pieceSize()) {
inPlace++; inPlace++;
if (inPlace == 25) if (inPlace == 25)
emit puzzleCompleted(); emit puzzleCompleted();
@ -139,8 +134,8 @@ void PuzzleWidget::dropEvent(QDropEvent *event)
int PuzzleWidget::findPiece(const QRect &pieceRect) const int PuzzleWidget::findPiece(const QRect &pieceRect) const
{ {
for (int i = 0; i < pieceRects.size(); ++i) { for (int i = 0, size = pieces.size(); i < size; ++i) {
if (pieceRect == pieceRects[i]) if (pieces.at(i).rect == pieceRect)
return i; return i;
} }
return -1; return -1;
@ -154,13 +149,9 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
if (found == -1) if (found == -1)
return; return;
QPoint location = pieceLocations[found]; Piece piece = pieces.takeAt(found);
QPixmap pixmap = piecePixmaps[found];
pieceLocations.removeAt(found);
piecePixmaps.removeAt(found);
pieceRects.removeAt(found);
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) if (piece.location == square.topLeft() / pieceSize())
inPlace--; inPlace--;
update(square); update(square);
@ -168,7 +159,7 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QByteArray itemData; QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly); QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << pixmap << location; dataStream << piece.pixmap << piece.location;
QMimeData *mimeData = new QMimeData; QMimeData *mimeData = new QMimeData;
mimeData->setData("image/x-puzzle-piece", itemData); mimeData->setData("image/x-puzzle-piece", itemData);
@ -176,23 +167,20 @@ void PuzzleWidget::mousePressEvent(QMouseEvent *event)
QDrag *drag = new QDrag(this); QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData); drag->setMimeData(mimeData);
drag->setHotSpot(event->pos() - square.topLeft()); drag->setHotSpot(event->pos() - square.topLeft());
drag->setPixmap(pixmap); drag->setPixmap(piece.pixmap);
if (drag->start(Qt::MoveAction) == 0) { if (drag->start(Qt::MoveAction) == Qt::IgnoreAction) {
pieceLocations.insert(found, location); pieces.insert(found, piece);
piecePixmaps.insert(found, pixmap);
pieceRects.insert(found, square);
update(targetSquare(event->pos())); update(targetSquare(event->pos()));
if (location == QPoint(square.x()/pieceSize(), square.y()/pieceSize())) if (piece.location == QPoint(square.x() / pieceSize(), square.y() / pieceSize()))
inPlace++; inPlace++;
} }
} }
void PuzzleWidget::paintEvent(QPaintEvent *event) void PuzzleWidget::paintEvent(QPaintEvent *event)
{ {
QPainter painter; QPainter painter(this);
painter.begin(this);
painter.fillRect(event->rect(), Qt::white); painter.fillRect(event->rect(), Qt::white);
if (highlightedRect.isValid()) { if (highlightedRect.isValid()) {
@ -201,15 +189,14 @@ void PuzzleWidget::paintEvent(QPaintEvent *event)
painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1)); painter.drawRect(highlightedRect.adjusted(0, 0, -1, -1));
} }
for (int i = 0; i < pieceRects.size(); ++i) { for (const Piece &piece : pieces)
painter.drawPixmap(pieceRects[i], piecePixmaps[i]); painter.drawPixmap(piece.rect, piece.pixmap);
}
painter.end();
} }
const QRect PuzzleWidget::targetSquare(const QPoint &position) const const QRect PuzzleWidget::targetSquare(const QPoint &position) const
{ {
return QRect(position.x()/pieceSize() * pieceSize(), position.y()/pieceSize() * pieceSize(), pieceSize(), pieceSize()); return QRect(position / pieceSize() * pieceSize(),
QSize(pieceSize(), pieceSize()));
} }
int PuzzleWidget::pieceSize() const int PuzzleWidget::pieceSize() const

View File

@ -51,9 +51,9 @@
#ifndef PUZZLEWIDGET_H #ifndef PUZZLEWIDGET_H
#define PUZZLEWIDGET_H #define PUZZLEWIDGET_H
#include <QList>
#include <QPixmap>
#include <QPoint> #include <QPoint>
#include <QPixmap>
#include <QVector>
#include <QWidget> #include <QWidget>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@ -67,7 +67,7 @@ class PuzzleWidget : public QWidget
Q_OBJECT Q_OBJECT
public: public:
explicit PuzzleWidget(int imageSize, QWidget *parent = 0); explicit PuzzleWidget(int imageSize, QWidget *parent = nullptr);
void clear(); void clear();
int pieceSize() const; int pieceSize() const;
@ -85,12 +85,16 @@ protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
private: private:
struct Piece {
QPixmap pixmap;
QRect rect;
QPoint location;
};
int findPiece(const QRect &pieceRect) const; int findPiece(const QRect &pieceRect) const;
const QRect targetSquare(const QPoint &position) const; const QRect targetSquare(const QPoint &position) const;
QList<QPixmap> piecePixmaps; QVector<Piece> pieces;
QList<QRect> pieceRects;
QList<QPoint> pieceLocations;
QRect highlightedRect; QRect highlightedRect;
int inPlace; int inPlace;
int m_ImageSize; int m_ImageSize;

View File

@ -129,6 +129,10 @@ PatternLineEdit::PatternLineEdit(QWidget *parent) :
connect(escapeSelectionAction, &QAction::triggered, this, &PatternLineEdit::escapeSelection); connect(escapeSelectionAction, &QAction::triggered, this, &PatternLineEdit::escapeSelection);
connect(copyToCodeAction, &QAction::triggered, this, &PatternLineEdit::copyToCode); connect(copyToCodeAction, &QAction::triggered, this, &PatternLineEdit::copyToCode);
connect(pasteFromCodeAction, &QAction::triggered, this, &PatternLineEdit::pasteFromCode); connect(pasteFromCodeAction, &QAction::triggered, this, &PatternLineEdit::pasteFromCode);
#if !QT_CONFIG(clipboard)
copyToCodeAction->setEnabled(false);
pasteFromCodeAction->setEnabled(false);
#endif
} }
void PatternLineEdit::escapeSelection() void PatternLineEdit::escapeSelection()
@ -144,12 +148,16 @@ void PatternLineEdit::escapeSelection()
void PatternLineEdit::copyToCode() void PatternLineEdit::copyToCode()
{ {
#if QT_CONFIG(clipboard)
QGuiApplication::clipboard()->setText(patternToCode(text())); QGuiApplication::clipboard()->setText(patternToCode(text()));
#endif
} }
void PatternLineEdit::pasteFromCode() void PatternLineEdit::pasteFromCode()
{ {
#if QT_CONFIG(clipboard)
setText(codeToPattern(QGuiApplication::clipboard()->text())); setText(codeToPattern(QGuiApplication::clipboard()->text()));
#endif
} }
void PatternLineEdit::contextMenuEvent(QContextMenuEvent *event) void PatternLineEdit::contextMenuEvent(QContextMenuEvent *event)
@ -316,7 +324,7 @@ void RegularExpressionDialog::refresh()
void RegularExpressionDialog::copyEscapedPatternToClipboard() void RegularExpressionDialog::copyEscapedPatternToClipboard()
{ {
#ifndef QT_NO_CLIPBOARD #if QT_CONFIG(clipboard)
QClipboard *clipboard = QGuiApplication::clipboard(); QClipboard *clipboard = QGuiApplication::clipboard();
if (clipboard) if (clipboard)
clipboard->setText(escapedPatternLineEdit->text()); clipboard->setText(escapedPatternLineEdit->text());
@ -361,7 +369,7 @@ QWidget *RegularExpressionDialog::setupLeftUi()
palette.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base)); palette.setBrush(QPalette::Base, palette.brush(QPalette::Disabled, QPalette::Base));
escapedPatternLineEdit->setPalette(palette); escapedPatternLineEdit->setPalette(palette);
#ifndef QT_NO_CLIPBOARD #if QT_CONFIG(clipboard)
QAction *copyEscapedPatternAction = new QAction(this); QAction *copyEscapedPatternAction = new QAction(this);
copyEscapedPatternAction->setText(tr("Copy to clipboard")); copyEscapedPatternAction->setText(tr("Copy to clipboard"));
copyEscapedPatternAction->setIcon(QIcon(QStringLiteral(":/images/copy.png"))); copyEscapedPatternAction->setIcon(QIcon(QStringLiteral(":/images/copy.png")));

View File

@ -1,10 +1,5 @@
win32 { cmake_version_output = $$system(cmake --version 2>$$QMAKE_SYSTEM_NULL_DEVICE, lines)
cmake_version_output = $$system(cmake --version 2>NUL, lines)
} else {
cmake_version_output = $$system(cmake --version 2>/dev/null, lines)
}
# First line # First line
cmake_version_output = $$first(cmake_version_output) cmake_version_output = $$first(cmake_version_output)
# Format is "cmake version X.Y.Z" # Format is "cmake version X.Y.Z"
@ -19,12 +14,7 @@ isEmpty(CMAKE_VERSION) {
return() return()
} }
win32 { CTEST_VERSION = $$system(ctest --version 2>$$QMAKE_SYSTEM_NULL_DEVICE)
CTEST_VERSION = $$system(ctest --version 2>NUL)
} else {
CTEST_VERSION = $$system(ctest --version 2>/dev/null)
}
isEmpty(CTEST_VERSION) { isEmpty(CTEST_VERSION) {
message("ctest executable not found. Not running CMake unit tests") message("ctest executable not found. Not running CMake unit tests")
return() return()

View File

@ -13,5 +13,6 @@
} }
$$add_plist: \ $$add_plist: \
QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote($$QMAKE_INFO_PLIST) QMAKE_LFLAGS += -Wl,-sectcreate,__TEXT,__info_plist,$$shell_quote( \
$$relative_path($$absolute_path($$QMAKE_INFO_PLIST, $$_PRO_FILE_PWD_), $$OUT_PWD))
} }

View File

@ -100,6 +100,9 @@ unix: CONFIG += explicitlib
# By default we want tests on macOS to be built as standalone executables # By default we want tests on macOS to be built as standalone executables
macos: CONFIG += testcase_no_bundle macos: CONFIG += testcase_no_bundle
# Override MinGW's definition in _mingw.h
mingw: DEFINES += WINVER=0x0601 _WIN32_WINNT=0x0601
defineTest(qtBuildPart) { defineTest(qtBuildPart) {
bp = $$eval($$upper($$section(_QMAKE_CONF_, /, -2, -2))_BUILD_PARTS) bp = $$eval($$upper($$section(_QMAKE_CONF_, /, -2, -2))_BUILD_PARTS)
isEmpty(bp): bp = $$QT_BUILD_PARTS isEmpty(bp): bp = $$QT_BUILD_PARTS

View File

@ -291,10 +291,7 @@ defineReplace(pkgConfigExecutable) {
} }
} }
equals(QMAKE_HOST.os, Windows): \ PKG_CONFIG += 2> $$QMAKE_SYSTEM_NULL_DEVICE
PKG_CONFIG += 2> NUL
else: \
PKG_CONFIG += 2> /dev/null
return($$PKG_CONFIG) return($$PKG_CONFIG)
} }

View File

@ -82,6 +82,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \
QMAKE_MKDIR = mkdir # legacy QMAKE_MKDIR = mkdir # legacy
QMAKE_MKDIR_CMD = if not exist %1 mkdir %1 & if not exist %1 exit 1 QMAKE_MKDIR_CMD = if not exist %1 mkdir %1 & if not exist %1 exit 1
QMAKE_STREAM_EDITOR = $(QMAKE) -install sed QMAKE_STREAM_EDITOR = $(QMAKE) -install sed
QMAKE_SHELL_NULL_DEVICE = NUL
QMAKE_INSTALL_FILE = copy /y QMAKE_INSTALL_FILE = copy /y
QMAKE_INSTALL_PROGRAM = copy /y QMAKE_INSTALL_PROGRAM = copy /y
} else { } else {
@ -101,6 +102,7 @@ equals(MAKEFILE_GENERATOR, MSBUILD) \
QMAKE_MKDIR = mkdir -p # legacy QMAKE_MKDIR = mkdir -p # legacy
QMAKE_MKDIR_CMD = test -d %1 || mkdir -p %1 QMAKE_MKDIR_CMD = test -d %1 || mkdir -p %1
QMAKE_STREAM_EDITOR = sed QMAKE_STREAM_EDITOR = sed
QMAKE_SHELL_NULL_DEVICE = /dev/null
equals(QMAKE_HOST.os, Windows) { equals(QMAKE_HOST.os, Windows) {
MINGW_IN_SHELL = 1 # legacy MINGW_IN_SHELL = 1 # legacy
@ -120,7 +122,9 @@ QMAKE_INSTALL_DIR = $$QMAKE_COPY_DIR
equals(QMAKE_HOST.os, Windows) { equals(QMAKE_HOST.os, Windows) {
QMAKE_SYMBOLIC_LINK = $(QMAKE) -install ln -f -s QMAKE_SYMBOLIC_LINK = $(QMAKE) -install ln -f -s
QMAKE_LN_SHLIB = $(QMAKE) -install ln -s QMAKE_LN_SHLIB = $(QMAKE) -install ln -s
QMAKE_SYSTEM_NULL_DEVICE = NUL
} else { } else {
QMAKE_SYMBOLIC_LINK = ln -f -s QMAKE_SYMBOLIC_LINK = ln -f -s
QMAKE_LN_SHLIB = ln -s QMAKE_LN_SHLIB = ln -s
QMAKE_SYSTEM_NULL_DEVICE = /dev/null
} }

View File

@ -32,15 +32,11 @@ isEmpty($${target_prefix}.INCDIRS) {
# Get default include and library paths from compiler # Get default include and library paths from compiler
# #
gcc { gcc {
!equals(QMAKE_HOST.os, Windows) { cmd_suffix = "<$$QMAKE_SYSTEM_NULL_DEVICE >$$QMAKE_SYSTEM_NULL_DEVICE"
cmd_prefix = "LC_ALL=C" equals(QMAKE_HOST.os, Windows): \
cmd_suffix = "</dev/null >/dev/null"
null_file = /dev/null
} else {
cmd_prefix = "set LC_ALL=C&" cmd_prefix = "set LC_ALL=C&"
cmd_suffix = "<NUL >NUL" else: \
null_file = NUL cmd_prefix = "LC_ALL=C"
}
cxx_flags = $$QMAKE_CXXFLAGS cxx_flags = $$QMAKE_CXXFLAGS
@ -59,7 +55,7 @@ isEmpty($${target_prefix}.INCDIRS) {
rim_qcc: \ rim_qcc: \
# Need the cc1plus and ld command lines to pick up the paths # Need the cc1plus and ld command lines to pick up the paths
cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$null_file -v cxx_flags += $$QMAKE_LFLAGS_SHLIB -o $$QMAKE_SYSTEM_NULL_DEVICE -v
else: darwin:clang: \ else: darwin:clang: \
# Need to link to pick up library paths # Need to link to pick up library paths
cxx_flags += $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v cxx_flags += $$QMAKE_LFLAGS_SHLIB -o /dev/null -v -Wl,-v
@ -175,9 +171,8 @@ defineReplace(qtVariablesFromMSVC) {
} }
defineReplace(qtVariablesFromGCC) { defineReplace(qtVariablesFromGCC) {
null_device = /dev/null ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) \
equals(QMAKE_HOST.os, Windows): null_device = NUL <$$QMAKE_SYSTEM_NULL_DEVICE 2>$$QMAKE_SYSTEM_NULL_DEVICE", lines, ec)
ret = $$system("$$1 -E $$system_quote($$PWD/data/macros.cpp) <$$null_device 2>$$null_device", lines, ec)
!equals(ec, 0): qtCompilerErrror($$1) !equals(ec, 0): qtCompilerErrror($$1)
return($$ret) return($$ret)
} }

View File

@ -36,12 +36,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#ifdef Q_OS_WIN
#define NULL_DEVICE "NUL"
#else
#define NULL_DEVICE "/dev/null"
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator() MingwMakefileGenerator::MingwMakefileGenerator() : Win32MakefileGenerator()
@ -329,7 +323,7 @@ void MingwMakefileGenerator::writeBuildRulesPart(QTextStream &t)
if(!project->isEmpty("QMAKE_PRE_LINK")) if(!project->isEmpty("QMAKE_PRE_LINK"))
t << "\n\t" <<var("QMAKE_PRE_LINK"); t << "\n\t" <<var("QMAKE_PRE_LINK");
if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") { if(project->isActiveConfig("staticlib") && project->first("TEMPLATE") == "lib") {
t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" NULL_DEVICE; t << "\n\t-$(DEL_FILE) $(DESTDIR_TARGET) 2>" << var("QMAKE_SHELL_NULL_DEVICE");
if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) { if (project->values("OBJECTS").count() < var("QMAKE_LINK_OBJECT_MAX").toInt()) {
t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ; t << "\n\t$(LIB) $(DESTDIR_TARGET) " << objectsLinkLine << " " ;
} else { } else {

View File

@ -1,32 +1,32 @@
// Copyright (C) 2002-2013 The ANGLE Project Authors. Copyright (C) 2002-2013 The ANGLE Project Authors.
// All rights reserved. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions modification, are permitted provided that the following conditions
// are met: are met:
//
// Redistributions of source code must retain the above copyright Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer. notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided disclaimer in the documentation and/or other materials provided
// with the distribution. with the distribution.
//
// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc.
// Ltd., nor the names of their contributors may be used to endorse Ltd., nor the names of their contributors may be used to endorse
// or promote products derived from this software without specific or promote products derived from this software without specific
// prior written permission. prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE. POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,15 @@
diff --git a/src/3rdparty/sqlite/sqlite3.c b/src/3rdparty/sqlite/sqlite3.c
index 7f5e75921f..f5c6180a03 100644
--- a/src/3rdparty/sqlite/sqlite3.c
+++ b/src/3rdparty/sqlite/sqlite3.c
@@ -165733,6 +165733,10 @@ static int getNodeSize(
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
+ }else if( pRtree->iNodeSize<(512-64) ){
+ rc = SQLITE_CORRUPT;
+ *pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
+ pRtree->zName);
}
}

View File

@ -165733,6 +165733,10 @@ static int getNodeSize(
rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize); rc = getIntFromStmt(db, zSql, &pRtree->iNodeSize);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
}else if( pRtree->iNodeSize<(512-64) ){
rc = SQLITE_CORRUPT;
*pzErr = sqlite3_mprintf("undersize RTree blobs in \"%q_node\"",
pRtree->zName);
} }
} }

View File

@ -585,7 +585,7 @@ angle_d3d11: SHADERS = VS_Passthrough2D \
for (SHADER, SHADERS) { for (SHADER, SHADERS) {
INPUT = $$eval($${SHADER}.input) INPUT = $$eval($${SHADER}.input)
OUT_DIR = $$OUT_PWD/libANGLE/$$relative_path($$dirname($$INPUT), $$ANGLE_DIR/src/libANGLE)/compiled OUT_DIR = $$OUT_PWD/libANGLE/$$relative_path($$dirname($$INPUT), $$ANGLE_DIR/src/libANGLE)/compiled
fxc_$${SHADER}.commands = $$FXC /nologo /E $${SHADER} /T $$eval($${SHADER}.type) /Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME} fxc_$${SHADER}.commands = $$FXC -nologo -E $${SHADER} -T $$eval($${SHADER}.type) -Fh ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
fxc_$${SHADER}.output = $$OUT_DIR/$$eval($${SHADER}.output) fxc_$${SHADER}.output = $$OUT_DIR/$$eval($${SHADER}.output)
fxc_$${SHADER}.input = $$INPUT fxc_$${SHADER}.input = $$INPUT
fxc_$${SHADER}.dependency_type = TYPE_C fxc_$${SHADER}.dependency_type = TYPE_C

View File

@ -48,8 +48,6 @@ win32 {
mingw { mingw {
# otherwise mingw headers do not declare common functions like putenv # otherwise mingw headers do not declare common functions like putenv
CONFIG -= strict_c++ CONFIG -= strict_c++
# Override MinGW's definition in _mingw.h
DEFINES += WINVER=0x600 _WIN32_WINNT=0x0600
} }
LIBS_PRIVATE += -lws2_32 LIBS_PRIVATE += -lws2_32
!winrt { !winrt {

View File

@ -99,8 +99,6 @@ gcc:ltcg {
SOURCES += $$VERSIONTAGGING_SOURCES SOURCES += $$VERSIONTAGGING_SOURCES
} }
# On AARCH64 the fp16 extension is mandatory, so we don't need the conversion tables.
!contains(QT_ARCH, "arm64") {
QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h QMAKE_QFLOAT16_TABLES_GENERATE = global/qfloat16.h
qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables) qtPrepareTool(QMAKE_QFLOAT16_TABLES, qfloat16-tables)
@ -111,4 +109,3 @@ gcc:ltcg {
qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE qfloat16_tables.input = QMAKE_QFLOAT16_TABLES_GENERATE
qfloat16_tables.variable_out = SOURCES qfloat16_tables.variable_out = SOURCES
QMAKE_EXTRA_COMPILERS += qfloat16_tables QMAKE_EXTRA_COMPILERS += qfloat16_tables
}

View File

@ -4296,6 +4296,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*! /*!
\macro qDebug(const char *message, ...) \macro qDebug(const char *message, ...)
\relates <QtGlobal> \relates <QtGlobal>
\threadsafe
Calls the message handler with the debug message \a message. If no Calls the message handler with the debug message \a message. If no
message handler has been installed, the message is printed to message handler has been installed, the message is printed to
@ -4332,6 +4333,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*! /*!
\macro qInfo(const char *message, ...) \macro qInfo(const char *message, ...)
\relates <QtGlobal> \relates <QtGlobal>
\threadsafe
\since 5.5 \since 5.5
Calls the message handler with the informational message \a message. If no Calls the message handler with the informational message \a message. If no
@ -4369,6 +4371,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*! /*!
\macro qWarning(const char *message, ...) \macro qWarning(const char *message, ...)
\relates <QtGlobal> \relates <QtGlobal>
\threadsafe
Calls the message handler with the warning message \a message. If no Calls the message handler with the warning message \a message. If no
message handler has been installed, the message is printed to message handler has been installed, the message is printed to
@ -4406,6 +4409,7 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
/*! /*!
\macro qCritical(const char *message, ...) \macro qCritical(const char *message, ...)
\relates <QtGlobal> \relates <QtGlobal>
\threadsafe
Calls the message handler with the critical message \a message. If no Calls the message handler with the critical message \a message. If no
message handler has been installed, the message is printed to message handler has been installed, the message is printed to

View File

@ -154,15 +154,19 @@ class SystemRandom
{ {
static QBasicAtomicInt s_fdp1; // "file descriptor plus 1" static QBasicAtomicInt s_fdp1; // "file descriptor plus 1"
static int openDevice(); static int openDevice();
#ifdef Q_CC_GNU
// If it's not GCC or GCC-like, then we'll leak the file descriptor
__attribute__((destructor))
#endif
static void closeDevice();
SystemRandom() {} SystemRandom() {}
~SystemRandom();
public: public:
enum { EfficientBufferFill = true }; enum { EfficientBufferFill = true };
static qssize_t fillBuffer(void *buffer, qssize_t count); static qssize_t fillBuffer(void *buffer, qssize_t count);
}; };
QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0); QBasicAtomicInt SystemRandom::s_fdp1 = Q_BASIC_ATOMIC_INITIALIZER(0);
SystemRandom::~SystemRandom() void SystemRandom::closeDevice()
{ {
int fd = s_fdp1.loadAcquire() - 1; int fd = s_fdp1.loadAcquire() - 1;
if (fd >= 0) if (fd >= 0)

View File

@ -62,8 +62,16 @@ public:
static Q_CORE_EXPORT quint64 generate64(); static Q_CORE_EXPORT quint64 generate64();
static double generateDouble() static double generateDouble()
{ {
// use get64() to get enough bits // IEEE 754 double precision has:
return double(generate64()) / ((std::numeric_limits<quint64>::max)() + double(1.0)); // 1 bit sign
// 10 bits exponent
// 53 bits mantissa
// In order for our result to be normalized in the range [0, 1), we
// need exactly 53 bits of random data. Use generate64() to get enough.
quint64 x = generate64();
quint64 limit = Q_UINT64_C(1) << std::numeric_limits<double>::digits;
x >>= std::numeric_limits<quint64>::digits - std::numeric_limits<double>::digits;
return double(x) / double(limit);
} }
static qreal bounded(qreal sup) static qreal bounded(qreal sup)

View File

@ -48,10 +48,10 @@
#if defined(Q_CC_MINGW) #if defined(Q_CC_MINGW)
// mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation // mingw's windows.h does not set _WIN32_WINNT, resulting breaking compilation
# ifndef WINVER # ifndef WINVER
# define WINVER 0x600 # define WINVER 0x601
# endif # endif
# ifndef _WIN32_WINNT # ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x600 # define _WIN32_WINNT 0x601
# endif # endif
# ifndef NTDDI_VERSION # ifndef NTDDI_VERSION
# define NTDDI_VERSION 0x06000000 # define NTDDI_VERSION 0x06000000

View File

@ -595,6 +595,9 @@ QByteArray QFileSystemEngine::id(const QFileSystemEntry &entry)
params.dwSize = sizeof(params); params.dwSize = sizeof(params);
params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL; params.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS; params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
params.dwSecurityQosFlags = SECURITY_ANONYMOUS;
params.lpSecurityAttributes = NULL;
params.hTemplateFile = NULL;
const HANDLE handle = const HANDLE handle =
CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), 0, CreateFile2((const wchar_t*)entry.nativeFilePath().utf16(), 0,
FILE_SHARE_READ, OPEN_EXISTING, &params); FILE_SHARE_READ, OPEN_EXISTING, &params);

View File

@ -445,6 +445,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCDebug(category) \macro qCDebug(category)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.2 \since 5.2
Returns an output stream for debug messages in the logging category Returns an output stream for debug messages in the logging category
@ -469,6 +470,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCDebug(category, const char *message, ...) \macro qCDebug(category, const char *message, ...)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.3 \since 5.3
Logs a debug message \a message in the logging category \a category. Logs a debug message \a message in the logging category \a category.
@ -490,6 +492,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCInfo(category) \macro qCInfo(category)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.5 \since 5.5
Returns an output stream for informational messages in the logging category Returns an output stream for informational messages in the logging category
@ -514,6 +517,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCInfo(category, const char *message, ...) \macro qCInfo(category, const char *message, ...)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.5 \since 5.5
Logs an informational message \a message in the logging category \a category. Logs an informational message \a message in the logging category \a category.
@ -535,6 +539,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCWarning(category) \macro qCWarning(category)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.2 \since 5.2
Returns an output stream for warning messages in the logging category Returns an output stream for warning messages in the logging category
@ -559,6 +564,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCWarning(category, const char *message, ...) \macro qCWarning(category, const char *message, ...)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.3 \since 5.3
Logs a warning message \a message in the logging category \a category. Logs a warning message \a message in the logging category \a category.
@ -580,6 +586,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCCritical(category) \macro qCCritical(category)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.2 \since 5.2
Returns an output stream for critical messages in the logging category Returns an output stream for critical messages in the logging category
@ -604,6 +611,7 @@ void QLoggingCategory::setFilterRules(const QString &rules)
/*! /*!
\macro qCCritical(category, const char *message, ...) \macro qCCritical(category, const char *message, ...)
\relates QLoggingCategory \relates QLoggingCategory
\threadsafe
\since 5.3 \since 5.3
Logs a critical message \a message in the logging category \a category. Logs a critical message \a message in the logging category \a category.

View File

@ -499,9 +499,10 @@ public:
InvalidFragmentError = Fragment << 8, InvalidFragmentError = Fragment << 8,
// the following two cases are only possible in combination // the following three cases are only possible in combination with
// with presence/absence of the authority and scheme. See validityError(). // presence/absence of the path, authority and scheme. See validityError().
AuthorityPresentAndPathIsRelative = Authority << 8 | Path << 8 | 0x10000, AuthorityPresentAndPathIsRelative = Authority << 8 | Path << 8 | 0x10000,
AuthorityAbsentAndPathIsDoubleSlash,
RelativeUrlPathContainsColonBeforeSlash = Scheme << 8 | Authority << 8 | Path << 8 | 0x10000, RelativeUrlPathContainsColonBeforeSlash = Scheme << 8 | Authority << 8 | Path << 8 | 0x10000,
NoError = 0 NoError = 0
@ -1627,19 +1628,32 @@ inline QUrlPrivate::ErrorCode QUrlPrivate::validityError(QString *source, int *p
return error->code; return error->code;
} }
// There are two more cases of invalid URLs that QUrl recognizes and they // There are three more cases of invalid URLs that QUrl recognizes and they
// are only possible with constructed URLs (setXXX methods), not with // are only possible with constructed URLs (setXXX methods), not with
// parsing. Therefore, they are tested here. // parsing. Therefore, they are tested here.
// //
// The two cases are a non-empty path that doesn't start with a slash and: // Two cases are a non-empty path that doesn't start with a slash and:
// - with an authority // - with an authority
// - without an authority, without scheme but the path with a colon before // - without an authority, without scheme but the path with a colon before
// the first slash // the first slash
// The third case is an empty authority and a non-empty path that starts
// with "//".
// Those cases are considered invalid because toString() would produce a URL // Those cases are considered invalid because toString() would produce a URL
// that wouldn't be parsed back to the same QUrl. // that wouldn't be parsed back to the same QUrl.
if (path.isEmpty() || path.at(0) == QLatin1Char('/')) if (path.isEmpty())
return NoError; return NoError;
if (path.at(0) == QLatin1Char('/')) {
if (sectionIsPresent & QUrlPrivate::Authority || port != -1 ||
path.length() == 1 || path.at(1) != QLatin1Char('/'))
return NoError;
if (source) {
*source = path;
*position = 0;
}
return AuthorityAbsentAndPathIsDoubleSlash;
}
if (sectionIsPresent & QUrlPrivate::Host) { if (sectionIsPresent & QUrlPrivate::Host) {
if (source) { if (source) {
*source = path; *source = path;
@ -2514,10 +2528,7 @@ void QUrl::setPath(const QString &path, ParsingMode mode)
mode = TolerantMode; mode = TolerantMode;
} }
int from = 0; d->setPath(data, 0, data.length());
while (from < data.length() - 2 && data.midRef(from, 2) == QLatin1String("//"))
++from;
d->setPath(data, from, data.length());
// optimized out, since there is no path delimiter // optimized out, since there is no path delimiter
// if (path.isNull()) // if (path.isNull())
@ -3989,6 +4000,8 @@ static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &err
case QUrlPrivate::AuthorityPresentAndPathIsRelative: case QUrlPrivate::AuthorityPresentAndPathIsRelative:
return QStringLiteral("Path component is relative and authority is present"); return QStringLiteral("Path component is relative and authority is present");
case QUrlPrivate::AuthorityAbsentAndPathIsDoubleSlash:
return QStringLiteral("Path component starts with '//' and authority is absent");
case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash: case QUrlPrivate::RelativeUrlPathContainsColonBeforeSlash:
return QStringLiteral("Relative URL's path component contains ':' before any '/'"); return QStringLiteral("Relative URL's path component contains ':' before any '/'");
} }

View File

@ -170,10 +170,10 @@ QT_BEGIN_NAMESPACE
\value LeaveEditFocus An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined. \value LeaveEditFocus An editor widget loses focus for editing. QT_KEYPAD_NAVIGATION must be defined.
\value LeaveWhatsThisMode Send to toplevel widgets when the application leaves "What's This?" mode. \value LeaveWhatsThisMode Send to toplevel widgets when the application leaves "What's This?" mode.
\value LocaleChange The system locale has changed. \value LocaleChange The system locale has changed.
\value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area. \value NonClientAreaMouseButtonDblClick A mouse double click occurred outside the client area (QMouseEvent).
\value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area. \value NonClientAreaMouseButtonPress A mouse button press occurred outside the client area (QMouseEvent).
\value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area. \value NonClientAreaMouseButtonRelease A mouse button release occurred outside the client area (QMouseEvent).
\value NonClientAreaMouseMove A mouse move occurred outside the client area. \value NonClientAreaMouseMove A mouse move occurred outside the client area (QMouseEvent).
\value MacSizeChange The user changed his widget sizes (\macos only). \value MacSizeChange The user changed his widget sizes (\macos only).
\value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod(). \value MetaCall An asynchronous method invocation via QMetaObject::invokeMethod().
\value ModifiedChange Widgets modification state has been changed. \value ModifiedChange Widgets modification state has been changed.

View File

@ -251,7 +251,7 @@ class Q_CORE_EXPORT QMutex
public: public:
enum RecursionMode { NonRecursive, Recursive }; enum RecursionMode { NonRecursive, Recursive };
inline explicit QMutex(RecursionMode mode = NonRecursive) Q_DECL_NOTHROW { Q_UNUSED(mode); } inline Q_DECL_CONSTEXPR explicit QMutex(RecursionMode = NonRecursive) Q_DECL_NOTHROW { }
inline void lock() Q_DECL_NOTHROW {} inline void lock() Q_DECL_NOTHROW {}
inline bool tryLock(int timeout = 0) Q_DECL_NOTHROW { Q_UNUSED(timeout); return true; } inline bool tryLock(int timeout = 0) Q_DECL_NOTHROW { Q_UNUSED(timeout); return true; }

View File

@ -73,7 +73,7 @@ public:
\internal \internal
*/ */
QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager) QThreadPoolThread::QThreadPoolThread(QThreadPoolPrivate *manager)
:manager(manager), runnable(0) :manager(manager), runnable(nullptr)
{ {
setStackSize(manager->stackSize); setStackSize(manager->stackSize);
} }
@ -86,7 +86,7 @@ void QThreadPoolThread::run()
QMutexLocker locker(&manager->mutex); QMutexLocker locker(&manager->mutex);
for(;;) { for(;;) {
QRunnable *r = runnable; QRunnable *r = runnable;
runnable = 0; runnable = nullptr;
do { do {
if (r) { if (r) {
@ -118,8 +118,19 @@ void QThreadPoolThread::run()
if (manager->tooManyThreadsActive()) if (manager->tooManyThreadsActive())
break; break;
r = !manager->queue.isEmpty() ? manager->queue.takeFirst().first : 0; if (manager->queue.isEmpty()) {
} while (r != 0); r = nullptr;
break;
}
QueuePage *page = manager->queue.first();
r = page->pop();
if (page->isFinished()) {
manager->queue.removeFirst();
delete page;
}
} while (true);
if (manager->isExiting) { if (manager->isExiting) {
registerThreadInactive(); registerThreadInactive();
@ -160,6 +171,7 @@ QThreadPoolPrivate:: QThreadPoolPrivate()
bool QThreadPoolPrivate::tryStart(QRunnable *task) bool QThreadPoolPrivate::tryStart(QRunnable *task)
{ {
Q_ASSERT(task != nullptr);
if (allThreads.isEmpty()) { if (allThreads.isEmpty()) {
// always create at least one thread // always create at least one thread
startThread(task); startThread(task);
@ -180,7 +192,7 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task)
if (!expiredThreads.isEmpty()) { if (!expiredThreads.isEmpty()) {
// restart an expired thread // restart an expired thread
QThreadPoolThread *thread = expiredThreads.dequeue(); QThreadPoolThread *thread = expiredThreads.dequeue();
Q_ASSERT(thread->runnable == 0); Q_ASSERT(thread->runnable == nullptr);
++activeThreads; ++activeThreads;
@ -196,22 +208,25 @@ bool QThreadPoolPrivate::tryStart(QRunnable *task)
return true; return true;
} }
inline bool operator<(int priority, const QPair<QRunnable *, int> &p) inline bool comparePriority(int priority, const QueuePage *p)
{ return p.second < priority; } {
inline bool operator<(const QPair<QRunnable *, int> &p, int priority) return p->priority() < priority;
{ return priority < p.second; } }
void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority)
{ {
Q_ASSERT(runnable != nullptr);
if (runnable->autoDelete()) if (runnable->autoDelete())
++runnable->ref; ++runnable->ref;
// put it on the queue for (QueuePage *page : qAsConst(queue)) {
QVector<QPair<QRunnable *, int> >::const_iterator begin = queue.constBegin(); if (page->priority() == priority && !page->isFull()) {
QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constEnd(); page->push(runnable);
if (it != begin && priority > (*(it - 1)).second) return;
it = std::upper_bound(begin, --it, priority); }
queue.insert(it - begin, qMakePair(runnable, priority)); }
auto it = std::upper_bound(queue.constBegin(), queue.constEnd(), priority, comparePriority);
queue.insert(std::distance(queue.constBegin(), it), new QueuePage(runnable, priority));
} }
int QThreadPoolPrivate::activeThreadCount() const int QThreadPoolPrivate::activeThreadCount() const
@ -225,8 +240,18 @@ int QThreadPoolPrivate::activeThreadCount() const
void QThreadPoolPrivate::tryToStartMoreThreads() void QThreadPoolPrivate::tryToStartMoreThreads()
{ {
// try to push tasks on the queue to any available threads // try to push tasks on the queue to any available threads
while (!queue.isEmpty() && tryStart(queue.constFirst().first)) while (!queue.isEmpty()) {
QueuePage *page = queue.first();
if (!tryStart(page->first()))
break;
page->pop();
if (page->isFinished()) {
queue.removeFirst(); queue.removeFirst();
delete page;
}
}
} }
bool QThreadPoolPrivate::tooManyThreadsActive() const bool QThreadPoolPrivate::tooManyThreadsActive() const
@ -240,6 +265,7 @@ bool QThreadPoolPrivate::tooManyThreadsActive() const
*/ */
void QThreadPoolPrivate::startThread(QRunnable *runnable) void QThreadPoolPrivate::startThread(QRunnable *runnable)
{ {
Q_ASSERT(runnable != nullptr);
QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this)); QScopedPointer <QThreadPoolThread> thread(new QThreadPoolThread(this));
thread->setObjectName(QLatin1String("Thread (pooled)")); thread->setObjectName(QLatin1String("Thread (pooled)"));
Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here) Q_ASSERT(!allThreads.contains(thread.data())); // if this assert hits, we have an ABA problem (deleted threads don't get removed here)
@ -303,12 +329,14 @@ bool QThreadPoolPrivate::waitForDone(int msecs)
void QThreadPoolPrivate::clear() void QThreadPoolPrivate::clear()
{ {
QMutexLocker locker(&mutex); QMutexLocker locker(&mutex);
for (QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constBegin(); for (QueuePage *page : qAsConst(queue)) {
it != queue.constEnd(); ++it) { while (!page->isFinished()) {
QRunnable* r = it->first; QRunnable *r = page->pop();
if (r->autoDelete() && !--r->ref) if (r && r->autoDelete() && !--r->ref)
delete r; delete r;
} }
}
qDeleteAll(queue);
queue.clear(); queue.clear();
} }
@ -333,22 +361,21 @@ bool QThreadPool::tryTake(QRunnable *runnable)
{ {
Q_D(QThreadPool); Q_D(QThreadPool);
if (runnable == 0) if (runnable == nullptr)
return false; return false;
{ {
QMutexLocker locker(&d->mutex); QMutexLocker locker(&d->mutex);
auto it = d->queue.begin(); for (QueuePage *page : qAsConst(d->queue)) {
auto end = d->queue.end(); if (page->tryTake(runnable)) {
if (page->isFinished()) {
while (it != end) { d->queue.removeOne(page);
if (it->first == runnable) { delete page;
d->queue.erase(it); }
if (runnable->autoDelete()) if (runnable->autoDelete())
--runnable->ref; // undo ++ref in start() --runnable->ref; // undo ++ref in start()
return true; return true;
} }
++it;
} }
} }

View File

@ -63,6 +63,87 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QueuePage {
public:
enum {
MaxPageSize = 256
};
QueuePage(QRunnable *runnable, int pri)
: m_priority(pri)
{
push(runnable);
}
bool isFull() {
return m_lastIndex >= MaxPageSize - 1;
}
bool isFinished() {
return m_firstIndex > m_lastIndex;
}
void push(QRunnable *runnable) {
Q_ASSERT(runnable != nullptr);
Q_ASSERT(!isFull());
m_lastIndex += 1;
m_entries[m_lastIndex] = runnable;
}
void skipToNextOrEnd() {
while (!isFinished() && m_entries[m_firstIndex] == nullptr) {
m_firstIndex += 1;
}
}
QRunnable *first() {
Q_ASSERT(!isFinished());
QRunnable *runnable = m_entries[m_firstIndex];
Q_ASSERT(runnable);
return runnable;
}
QRunnable *pop() {
Q_ASSERT(!isFinished());
QRunnable *runnable = first();
Q_ASSERT(runnable);
// clear the entry although this should not be necessary
m_entries[m_firstIndex] = nullptr;
m_firstIndex += 1;
// make sure the next runnable returned by first() is not a nullptr
skipToNextOrEnd();
return runnable;
}
bool tryTake(QRunnable *runnable) {
Q_ASSERT(!isFinished());
for (int i = m_firstIndex; i <= m_lastIndex; i++) {
if (m_entries[i] == runnable) {
m_entries[i] = nullptr;
if (i == m_firstIndex) {
// make sure first() does not return a nullptr
skipToNextOrEnd();
}
return true;
}
}
return false;
}
int priority() const {
return m_priority;
}
private:
int m_priority = 0;
int m_firstIndex = 0;
int m_lastIndex = -1;
QRunnable *m_entries[MaxPageSize];
};
class QThreadPoolThread; class QThreadPoolThread;
class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate class Q_CORE_EXPORT QThreadPoolPrivate : public QObjectPrivate
{ {
@ -84,12 +165,13 @@ public:
bool waitForDone(int msecs); bool waitForDone(int msecs);
void clear(); void clear();
void stealAndRunRunnable(QRunnable *runnable); void stealAndRunRunnable(QRunnable *runnable);
void deletePageIfFinished(QueuePage *page);
mutable QMutex mutex; mutable QMutex mutex;
QList<QThreadPoolThread *> allThreads; QList<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads; QQueue<QThreadPoolThread *> waitingThreads;
QQueue<QThreadPoolThread *> expiredThreads; QQueue<QThreadPoolThread *> expiredThreads;
QVector<QPair<QRunnable *, int> > queue; QVector<QueuePage*> queue;
QWaitCondition noActiveThreads; QWaitCondition noActiveThreads;
int expiryTimeout = 30000; int expiryTimeout = 30000;

View File

@ -195,7 +195,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtDBus \inmodule QtDBus
\brief Information about one interface on the bus. \brief Information about one interface on the bus.
Each interface on D-Bus has an unique \a name, identifying where that interface was defined. Each interface on D-Bus has a unique \a name, identifying where that interface was defined.
Interfaces may have annotations, methods, signals and properties, but none are mandatory. Interfaces may have annotations, methods, signals and properties, but none are mandatory.
*/ */

View File

@ -228,7 +228,6 @@ Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf, void QDBusMetaType::registerMarshallOperators(int id, MarshallFunction mf,
DemarshallFunction df) DemarshallFunction df)
{ {
QByteArray var;
QVector<QDBusCustomTypeInfo> *ct = customTypes(); QVector<QDBusCustomTypeInfo> *ct = customTypes();
if (id < 0 || !mf || !df || !ct) if (id < 0 || !mf || !df || !ct)
return; // error! return; // error!

View File

@ -1124,7 +1124,7 @@ QWheelEvent::QWheelEvent(const QPointF &pos, const QPointF& globalPos,
The event is propagated up the parent widget chain until a widget The event is propagated up the parent widget chain until a widget
accepts it or an event filter consumes it. accepts it or an event filter consumes it.
The QWidget::setEnable() function can be used to enable or disable The QWidget::setEnabled() function can be used to enable or disable
mouse and keyboard events for a widget. mouse and keyboard events for a widget.
The event handlers QWidget::keyPressEvent(), QWidget::keyReleaseEvent(), The event handlers QWidget::keyPressEvent(), QWidget::keyReleaseEvent(),
@ -2335,6 +2335,13 @@ QVariant QInputMethodQueryEvent::value(Qt::InputMethodQuery query) const
cursor and touchpad. Qt recognizes these by their names. Otherwise, if the cursor and touchpad. Qt recognizes these by their names. Otherwise, if the
tablet is configured to use the evdev driver, there will be only one device tablet is configured to use the evdev driver, there will be only one device
and applications may not be able to distinguish the stylus from the eraser. and applications may not be able to distinguish the stylus from the eraser.
\section1 Notes for Windows Users
Tablet support currently requires the WACOM windows driver providing the DLL
\c{wintab32.dll} to be installed. It is contained in older packages,
for example \c{pentablet_5.3.5-3.exe}.
*/ */
/*! /*!
@ -2783,13 +2790,13 @@ Q_GLOBAL_STATIC(NativeGestureEventDataHash, g_nativeGestureEventDataHash)
\a realValue is the \macos event parameter, \a sequenceId and \a intValue are the Windows event parameters. \a realValue is the \macos event parameter, \a sequenceId and \a intValue are the Windows event parameters.
\since 5.10 \since 5.10
*/ */
QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *dev, const QPointF &localPos, const QPointF &windowPos, QNativeGestureEvent::QNativeGestureEvent(Qt::NativeGestureType type, const QTouchDevice *device, const QPointF &localPos, const QPointF &windowPos,
const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue) const QPointF &screenPos, qreal realValue, ulong sequenceId, quint64 intValue)
: QInputEvent(QEvent::NativeGesture), mGestureType(type), : QInputEvent(QEvent::NativeGesture), mGestureType(type),
mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue), mLocalPos(localPos), mWindowPos(windowPos), mScreenPos(screenPos), mRealValue(realValue),
mSequenceId(sequenceId), mIntValue(intValue) mSequenceId(sequenceId), mIntValue(intValue)
{ {
g_nativeGestureEventDataHash->insert(this, dev); g_nativeGestureEventDataHash->insert(this, device);
} }
QNativeGestureEvent::~QNativeGestureEvent() QNativeGestureEvent::~QNativeGestureEvent()

View File

@ -531,7 +531,7 @@ QVariant QPlatformTheme::defaultThemeHint(ThemeHint hint)
case UiEffects: case UiEffects:
return QVariant(int(0)); return QVariant(int(0));
case SpellCheckUnderlineStyle: case SpellCheckUnderlineStyle:
return QVariant(int(QTextCharFormat::SpellCheckUnderline)); return QVariant(int(QTextCharFormat::WaveUnderline));
case TabFocusBehavior: case TabFocusBehavior:
return QVariant(int(Qt::TabFocusAllControls)); return QVariant(int(Qt::TabFocusAllControls));
case IconPixmapSizes: case IconPixmapSizes:

View File

@ -5572,6 +5572,8 @@ static void qt_alphamapblit_generic(QRasterBuffer *rasterBuffer,
int start = qMax<int>(x, clip.x); int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len); int end = qMin<int>(x + mapWidth, clip.x + clip.len);
if (end <= start)
continue;
Q_ASSERT(end - start <= buffer_size); Q_ASSERT(end - start <= buffer_size);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start);
@ -5845,6 +5847,8 @@ static void qt_alphargbblit_generic(QRasterBuffer *rasterBuffer,
int start = qMax<int>(x, clip.x); int start = qMax<int>(x, clip.x);
int end = qMin<int>(x + mapWidth, clip.x + clip.len); int end = qMin<int>(x + mapWidth, clip.x + clip.len);
if (end <= start)
continue;
Q_ASSERT(end - start <= buffer_size); Q_ASSERT(end - start <= buffer_size);
QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start); QRgba64 *dest = destFetch64((QRgba64*)buffer, rasterBuffer, start, clip.y, end - start);

View File

@ -1638,7 +1638,7 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
QPointF p = lines[i].p1(); QPointF p = lines[i].p1();
QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()), QLineF line = s->matrix.map(QLineF(QPointF(p.x() - width*0.5, p.y()),
QPointF(p.x() + width*0.5, p.y()))); QPointF(p.x() + width*0.5, p.y())));
d->rasterizer->rasterizeLine(line.p1(), line.p2(), 1); d->rasterizer->rasterizeLine(line.p1(), line.p2(), width / line.length());
} }
continue; continue;
} }

View File

@ -6261,6 +6261,8 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme(); QPlatformTheme *theme = QGuiApplicationPrivate::platformTheme();
if (theme) if (theme)
underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt()); underlineStyle = QTextCharFormat::UnderlineStyle(theme->themeHint(QPlatformTheme::SpellCheckUnderlineStyle).toInt());
if (underlineStyle == QTextCharFormat::SpellCheckUnderline) // still not resolved
underlineStyle = QTextCharFormat::WaveUnderline;
} }
if (underlineStyle == QTextCharFormat::WaveUnderline) { if (underlineStyle == QTextCharFormat::WaveUnderline) {

View File

@ -1147,8 +1147,6 @@ void QDashStroker::processCurrentSubpath()
QLineF cline; QLineF cline;
QPainterPath dashPath;
QSubpathFlatIterator it(&m_elements, m_dashThreshold); QSubpathFlatIterator it(&m_elements, m_dashThreshold);
qfixed2d prev = it.next(); qfixed2d prev = it.next();

View File

@ -1333,9 +1333,9 @@ bool QTextFormat::operator==(const QTextFormat &rhs) const
\value DashDotLine Dashs and dots are drawn using Qt::DashDotLine. \value DashDotLine Dashs and dots are drawn using Qt::DashDotLine.
\value DashDotDotLine Underlines draw drawn using Qt::DashDotDotLine. \value DashDotDotLine Underlines draw drawn using Qt::DashDotDotLine.
\value WaveUnderline The text is underlined using a wave shaped line. \value WaveUnderline The text is underlined using a wave shaped line.
\value SpellCheckUnderline The underline is drawn depending on the QStyle::SH_SpellCeckUnderlineStyle \value SpellCheckUnderline The underline is drawn depending on the SpellCheckUnderlineStyle
style hint of the QApplication style. By default this is mapped to theme hint of QPlatformTheme. By default this is mapped to
WaveUnderline, on \macos it is mapped to DashDotLine. WaveUnderline, on \macos it is mapped to DotLine.
\sa Qt::PenStyle \sa Qt::PenStyle
*/ */

View File

@ -381,7 +381,6 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF
} }
if (image.isNull()) { if (image.isNull()) {
QString context;
if (image.isNull()) { // try direct loading if (image.isNull()) { // try direct loading
name = imageFormat.name(); // remove qrc:/ prefix again name = imageFormat.name(); // remove qrc:/ prefix again
image.load(name); image.load(name);

View File

@ -1051,10 +1051,12 @@ void QGridLayoutEngine::setGeometries(const QRectF &contentsGeometry, const QAbs
if (m_snapToPixelGrid) { if (m_snapToPixelGrid) {
// x and y should already be rounded, but the call to geometryWithin() above might // x and y should already be rounded, but the call to geometryWithin() above might
// result in a geom with x,y at half-pixels (due to centering within the cell) // result in a geom with x,y at half-pixels (due to centering within the cell)
geom.setX(qround(geom.x())); // QRectF may change the width as it wants to maintain the right edge. In this
// case the width need to be preserved.
geom.moveLeft(qround(geom.x()));
// Do not snap baseline aligned items, since that might cause the baselines to not be aligned. // Do not snap baseline aligned items, since that might cause the baselines to not be aligned.
if (align != Qt::AlignBaseline) if (align != Qt::AlignBaseline)
geom.setY(qround(geom.y())); geom.moveTop(qround(geom.y()));
} }
visualRect(&geom, visualDirection(), contentsGeometry); visualRect(&geom, visualDirection(), contentsGeometry);
item->setGeometry(geom); item->setGeometry(geom);

View File

@ -59,7 +59,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
// internal helper. Converts an integer value to an unique string token // internal helper. Converts an integer value to a unique string token
template <typename T> template <typename T>
struct HexString struct HexString
{ {

View File

@ -114,7 +114,7 @@ void QHstsStore::synchronize()
if (observedPolicies.size()) { if (observedPolicies.size()) {
beginHstsGroups(); beginHstsGroups();
for (const QHstsPolicy &policy : observedPolicies) { for (const QHstsPolicy &policy : qAsConst(observedPolicies)) {
const QString key(host_name_to_settings_key(policy.host())); const QString key(host_name_to_settings_key(policy.host()));
// If we fail to write a new, updated policy, we also remove the old one. // If we fail to write a new, updated policy, we also remove the old one.
if (policy.isExpired() || !serializePolicy(key, policy)) if (policy.isExpired() || !serializePolicy(key, policy))

View File

@ -476,6 +476,8 @@ bool QHttpMultiPartIODevice::isSequential() const
bool QHttpMultiPartIODevice::reset() bool QHttpMultiPartIODevice::reset()
{ {
// Reset QIODevice's data
QIODevice::reset();
for (int a = 0; a < multiPart->parts.count(); a++) for (int a = 0; a < multiPart->parts.count(); a++)
if (!multiPart->parts[a].d->reset()) if (!multiPart->parts[a].d->reset())
return false; return false;

View File

@ -604,14 +604,21 @@ void QHttpNetworkConnectionChannel::handleStatus()
case 302: case 302:
case 303: case 303:
case 305: case 305:
case 307: { case 307:
case 308: {
// Parse the response headers and get the "location" url // Parse the response headers and get the "location" url
QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply); QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply);
if (redirectUrl.isValid()) if (redirectUrl.isValid())
reply->setRedirectUrl(redirectUrl); reply->setRedirectUrl(redirectUrl);
if (qobject_cast<QHttpNetworkConnection *>(connection)) if ((statusCode == 307 || statusCode == 308) && !resetUploadData()) {
// Couldn't reset the upload data, which means it will be unable to POST the data -
// this would lead to a long wait until it eventually failed and then retried.
// Instead of doing that we fail here instead, resetUploadData will already have emitted
// a ContentReSendError, so we're done.
} else if (qobject_cast<QHttpNetworkConnection *>(connection)) {
QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection); QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
}
break; break;
} }
case 401: // auth required case 401: // auth required

View File

@ -96,7 +96,7 @@ void QHttpNetworkReply::setRedirectUrl(const QUrl &url)
bool QHttpNetworkReply::isHttpRedirect(int statusCode) bool QHttpNetworkReply::isHttpRedirect(int statusCode)
{ {
return (statusCode == 301 || statusCode == 302 || statusCode == 303 return (statusCode == 301 || statusCode == 302 || statusCode == 303
|| statusCode == 305 || statusCode == 307); || statusCode == 305 || statusCode == 307 || statusCode == 308);
} }
qint64 QHttpNetworkReply::contentLength() const qint64 QHttpNetworkReply::contentLength() const

View File

@ -140,7 +140,7 @@ void QNetworkCookieJar::setAllCookies(const QList<QNetworkCookie> &cookieList)
static inline bool isParentPath(const QString &path, const QString &reference) static inline bool isParentPath(const QString &path, const QString &reference)
{ {
if (path.startsWith(reference)) { if ((path.isEmpty() && reference == QLatin1String("/")) || path.startsWith(reference)) {
//The cookie-path and the request-path are identical. //The cookie-path and the request-path are identical.
if (path.length() == reference.length()) if (path.length() == reference.length())
return true; return true;

View File

@ -297,7 +297,7 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was
set in the request and the server responded with a 3xx status (specifically set in the request and the server responded with a 3xx status (specifically
301, 302, 303, 305 or 307 status code) with a valid url in the location 301, 302, 303, 305, 307 or 308 status code) with a valid url in the location
header, indicating a HTTP redirect. The \a url parameter contains the new header, indicating a HTTP redirect. The \a url parameter contains the new
redirect url as returned by the server in the location header. redirect url as returned by the server in the location header.

View File

@ -165,6 +165,16 @@ static QHash<QByteArray, QByteArray> parseHttpOptionHeader(const QByteArray &hea
} }
} }
#if QT_CONFIG(bearermanagement)
static bool isSessionNeeded(const QUrl &url)
{
// Connections to the local machine does not require a session
QString host = url.host().toLower();
return !QHostAddress(host).isLoopback() && host != QLatin1String("localhost")
&& host != QSysInfo::machineHostName().toLower();
}
#endif // bearer management
QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager, QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manager,
const QNetworkRequest& request, const QNetworkRequest& request,
QNetworkAccessManager::Operation& operation, QNetworkAccessManager::Operation& operation,
@ -1115,10 +1125,15 @@ QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperat
switch (currentOp) { switch (currentOp) {
case QNetworkAccessManager::HeadOperation: case QNetworkAccessManager::HeadOperation:
return QNetworkAccessManager::HeadOperation; return QNetworkAccessManager::HeadOperation;
case QNetworkAccessManager::PostOperation:
// We MUST keep using POST when being redirected with 307 or 308.
if (statusCode == 307 || statusCode == 308)
return QNetworkAccessManager::PostOperation;
break;
default: default:
break; break;
} }
// For now, we're always returning GET for anything other than HEAD // Use GET for everything else.
return QNetworkAccessManager::GetOperation; return QNetworkAccessManager::GetOperation;
} }
@ -1193,11 +1208,30 @@ void QNetworkReplyHttpImplPrivate::followRedirect()
{ {
Q_Q(QNetworkReplyHttpImpl); Q_Q(QNetworkReplyHttpImpl);
rawHeaders.clear();
cookedHeaders.clear(); cookedHeaders.clear();
if (managerPrivate->thread) if (managerPrivate->thread)
managerPrivate->thread->disconnect(); managerPrivate->thread->disconnect();
#if QT_CONFIG(bearermanagement)
// If the original request didn't need a session (i.e. it was to localhost)
// then we might not have a session open, to which to redirect, if the
// new URL is remote. When this happens, we need to open the session now:
if (managerPrivate && isSessionNeeded(url)) {
if (auto session = managerPrivate->getNetworkSession()) {
if (session->state() != QNetworkSession::State::Connected || !session->isOpen()) {
startWaitForSession(session);
// Need to set 'request' to the redirectRequest so that when QNAM restarts
// the request after the session starts it will not repeat the previous request.
request = redirectRequest;
// Return now, QNAM will start the request when the session has started.
return;
}
}
}
#endif // bearer management
QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection, QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection,
Q_ARG(QNetworkRequest, redirectRequest)); Q_ARG(QNetworkRequest, redirectRequest));
} }
@ -1210,6 +1244,7 @@ void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
case 302: // Found case 302: // Found
case 303: // See Other case 303: // See Other
case 307: // Temporary Redirect case 307: // Temporary Redirect
case 308: // Permanent Redirect
// What do we do about the caching of the HTML note? // What do we do about the caching of the HTML note?
// The response to a 303 MUST NOT be cached, while the response to // The response to a 303 MUST NOT be cached, while the response to
// all of the others is cacheable if the headers indicate it to be // all of the others is cacheable if the headers indicate it to be
@ -1783,10 +1818,8 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
} }
// This is not ideal. // This is not ideal.
const QString host = url.host(); if (!isSessionNeeded(url)) {
if (host == QLatin1String("localhost") || // Don't need to check for an open session if we don't need one.
QHostAddress(host).isLoopback()) {
// Don't need an open session for localhost access.
postRequest(newHttpRequest); postRequest(newHttpRequest);
return true; return true;
} }
@ -1810,6 +1843,34 @@ bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
#endif #endif
} }
#if QT_CONFIG(bearermanagement)
bool QNetworkReplyHttpImplPrivate::startWaitForSession(QSharedPointer<QNetworkSession> &session)
{
Q_Q(QNetworkReplyHttpImpl);
state = WaitingForSession;
if (session) {
QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
if (!session->isOpen()) {
QVariant isBackground = request.attribute(QNetworkRequest::BackgroundRequestAttribute,
QVariant::fromValue(false));
session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
session->open();
}
return true;
}
const Qt::ConnectionType connection = synchronous ? Qt::DirectConnection : Qt::QueuedConnection;
qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
QMetaObject::invokeMethod(q, "_q_error", connection,
Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
QMetaObject::invokeMethod(q, "_q_finished", connection);
return false;
}
#endif // QT_CONFIG(bearermanagement)
void QNetworkReplyHttpImplPrivate::_q_startOperation() void QNetworkReplyHttpImplPrivate::_q_startOperation()
{ {
Q_Q(QNetworkReplyHttpImpl); Q_Q(QNetworkReplyHttpImpl);
@ -1837,24 +1898,8 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
// backend failed to start because the session state is not Connected. // backend failed to start because the session state is not Connected.
// QNetworkAccessManager will call reply->backend->start() again for us when the session // QNetworkAccessManager will call reply->backend->start() again for us when the session
// state changes. // state changes.
state = WaitingForSession; if (!startWaitForSession(session))
if (session) {
QObject::connect(session.data(), SIGNAL(error(QNetworkSession::SessionError)),
q, SLOT(_q_networkSessionFailed()), Qt::QueuedConnection);
if (!session->isOpen()) {
session->setSessionProperty(QStringLiteral("ConnectInBackground"), isBackground);
session->open();
}
} else {
qWarning("Backend is waiting for QNetworkSession to connect, but there is none!");
QMetaObject::invokeMethod(q, "_q_error", synchronous ? Qt::DirectConnection : Qt::QueuedConnection,
Q_ARG(QNetworkReply::NetworkError, QNetworkReply::NetworkSessionFailedError),
Q_ARG(QString, QCoreApplication::translate("QNetworkReply", "Network session error.")));
QMetaObject::invokeMethod(q, "_q_finished", synchronous ? Qt::DirectConnection : Qt::QueuedConnection);
return; return;
}
} else if (session) { } else if (session) {
QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)), QObject::connect(session.data(), SIGNAL(stateChanged(QNetworkSession::State)),
q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)),

View File

@ -161,6 +161,10 @@ signals:
class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate class QNetworkReplyHttpImplPrivate: public QNetworkReplyPrivate
{ {
#if QT_CONFIG(bearermanagement)
bool startWaitForSession(QSharedPointer<QNetworkSession> &session);
#endif
public: public:
static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio); static QHttpNetworkRequest::Priority convert(const QNetworkRequest::Priority& prio);

View File

@ -89,31 +89,6 @@
}, },
"tests": { "tests": {
"getaddrinfo": {
"label": "getaddrinfo()",
"type": "compile",
"test": {
"head": [
"#include <stdio.h>",
"#include <stdlib.h>",
"#ifdef __MINGW32__",
"# include <winsock2.h>",
"# include <ws2tcpip.h>",
"#else",
"# include <sys/types.h>",
"# include <sys/socket.h>",
"# include <netdb.h>",
"#endif"
],
"main": [
"addrinfo *res = 0;",
"(void) getaddrinfo(\"foo\", 0, 0, &res);",
"freeaddrinfo(res);",
"gai_strerror(0);"
]
},
"use": "network"
},
"getifaddrs": { "getifaddrs": {
"label": "getifaddrs()", "label": "getifaddrs()",
"type": "compile", "type": "compile",
@ -170,11 +145,6 @@
"emitIf": "config.darwin", "emitIf": "config.darwin",
"output": [ "feature", "privateFeature" ] "output": [ "feature", "privateFeature" ]
}, },
"getaddrinfo": {
"label": "getaddrinfo()",
"condition": "tests.getaddrinfo",
"output": [ "feature" ]
},
"getifaddrs": { "getifaddrs": {
"label": "getifaddrs()", "label": "getifaddrs()",
"condition": "tests.getifaddrs", "condition": "tests.getifaddrs",
@ -337,7 +307,7 @@ For example:
"args": "corewlan", "args": "corewlan",
"condition": "config.darwin" "condition": "config.darwin"
}, },
"getaddrinfo", "getifaddrs", "ipv6ifname", "libproxy", "getifaddrs", "ipv6ifname", "libproxy",
{ {
"type": "feature", "type": "feature",
"args": "securetransport", "args": "securetransport",

View File

@ -49,8 +49,6 @@ win32: {
SOURCES += kernel/qdnslookup_win.cpp \ SOURCES += kernel/qdnslookup_win.cpp \
kernel/qnetworkinterface_win.cpp kernel/qnetworkinterface_win.cpp
LIBS_PRIVATE += -ldnsapi -liphlpapi LIBS_PRIVATE += -ldnsapi -liphlpapi
DEFINES += WINVER=0x0600 _WIN32_WINNT=0x0600
} else { } else {
SOURCES += kernel/qdnslookup_winrt.cpp \ SOURCES += kernel/qdnslookup_winrt.cpp \
kernel/qnetworkinterface_winrt.cpp kernel/qnetworkinterface_winrt.cpp

View File

@ -533,49 +533,6 @@ QHostAddress::QHostAddress(SpecialAddress address)
setAddress(address); setAddress(address);
} }
/*!
\overload
\since 5.8
Sets the special address specified by \a address.
*/
void QHostAddress::setAddress(SpecialAddress address)
{
d->clear();
Q_IPV6ADDR ip6;
memset(&ip6, 0, sizeof ip6);
quint32 ip4 = INADDR_ANY;
switch (address) {
case Null:
return;
case Broadcast:
ip4 = INADDR_BROADCAST;
break;
case LocalHost:
ip4 = INADDR_LOOPBACK;
break;
case AnyIPv4:
break;
case LocalHostIPv6:
ip6[15] = 1;
Q_FALLTHROUGH();
case AnyIPv6:
d->setAddress(ip6);
return;
case Any:
d->protocol = QAbstractSocket::AnyIPProtocol;
return;
}
// common IPv4 part
d->setAddress(ip4);
}
/*! /*!
Destroys the host address object. Destroys the host address object.
*/ */
@ -739,6 +696,49 @@ void QHostAddress::setAddress(const struct sockaddr *sockaddr)
#endif #endif
} }
/*!
\overload
\since 5.8
Sets the special address specified by \a address.
*/
void QHostAddress::setAddress(SpecialAddress address)
{
clear();
Q_IPV6ADDR ip6;
memset(&ip6, 0, sizeof ip6);
quint32 ip4 = INADDR_ANY;
switch (address) {
case Null:
return;
case Broadcast:
ip4 = INADDR_BROADCAST;
break;
case LocalHost:
ip4 = INADDR_LOOPBACK;
break;
case AnyIPv4:
break;
case LocalHostIPv6:
ip6[15] = 1;
Q_FALLTHROUGH();
case AnyIPv6:
d->setAddress(ip6);
return;
case Any:
d->protocol = QAbstractSocket::AnyIPProtocol;
return;
}
// common IPv4 part
d->setAddress(ip4);
}
/*! /*!
Returns the IPv4 address as a number. Returns the IPv4 address as a number.

View File

@ -66,10 +66,6 @@
# include <gnu/lib-names.h> # include <gnu/lib-names.h>
#endif #endif
#if defined (QT_NO_GETADDRINFO)
static QBasicMutex getHostByNameMutex;
#endif
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
// Almost always the same. If not, specify in qplatformdefs.h. // Almost always the same. If not, specify in qplatformdefs.h.
@ -188,7 +184,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
QHostAddress address; QHostAddress address;
if (address.setAddress(hostName)) { if (address.setAddress(hostName)) {
// Reverse lookup // Reverse lookup
#if !defined (QT_NO_GETADDRINFO)
sockaddr_in sa4; sockaddr_in sa4;
sockaddr_in6 sa6; sockaddr_in6 sa6;
sockaddr *sa = 0; sockaddr *sa = 0;
@ -211,12 +206,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
char hbuf[NI_MAXHOST]; char hbuf[NI_MAXHOST];
if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
results.setHostName(QString::fromLatin1(hbuf)); results.setHostName(QString::fromLatin1(hbuf));
#else
in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData());
struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET);
if (ent)
results.setHostName(QString::fromLatin1(ent->h_name));
#endif
if (results.hostName().isEmpty()) if (results.hostName().isEmpty())
results.setHostName(address.toString()); results.setHostName(address.toString());
@ -235,7 +224,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results; return results;
} }
#if !defined (QT_NO_GETADDRINFO)
// Call getaddrinfo, and place all IPv4 addresses at the start and // Call getaddrinfo, and place all IPv4 addresses at the start and
// the IPv6 addresses at the end of the address list in results. // the IPv6 addresses at the end of the address list in results.
addrinfo *res = 0; addrinfo *res = 0;
@ -302,39 +290,6 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
} }
#else
// Fall back to gethostbyname for platforms that don't define
// getaddrinfo. gethostbyname does not support IPv6, and it's not
// reentrant on all platforms. For now this is okay since we only
// use one QHostInfoAgent, but if more agents are introduced, locking
// must be provided.
QMutexLocker locker(&getHostByNameMutex);
hostent *result = gethostbyname(aceHostname.constData());
if (result) {
if (result->h_addrtype == AF_INET) {
QList<QHostAddress> addresses;
for (char **p = result->h_addr_list; *p != 0; p++) {
QHostAddress addr;
addr.setAddress(ntohl(*((quint32 *)*p)));
if (!addresses.contains(addr))
addresses.prepend(addr);
}
results.setAddresses(addresses);
} else {
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown address type"));
}
#if !defined(Q_OS_VXWORKS)
} else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA
|| h_errno == NO_ADDRESS) {
results.setError(QHostInfo::HostNotFound);
results.setErrorString(tr("Host not found"));
#endif
} else {
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown error"));
}
#endif // !defined (QT_NO_GETADDRINFO)
#if defined(QHOSTINFO_DEBUG) #if defined(QHOSTINFO_DEBUG)
if (results.error() != QHostInfo::NoError) { if (results.error() != QHostInfo::NoError) {
@ -377,11 +332,6 @@ QString QHostInfo::localDomainName()
if (local_res_init && local_res) { if (local_res_init && local_res) {
// using thread-unsafe version // using thread-unsafe version
#if defined(QT_NO_GETADDRINFO)
// We have to call res_init to be sure that _res was initialized
// So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too
QMutexLocker locker(&getHostByNameMutex);
#endif
local_res_init(); local_res_init();
QString domainName = QUrl::fromAce(local_res->defdname); QString domainName = QUrl::fromAce(local_res->defdname);
if (domainName.isEmpty()) if (domainName.isEmpty())

View File

@ -50,50 +50,12 @@ QT_BEGIN_NAMESPACE
//#define QHOSTINFO_DEBUG //#define QHOSTINFO_DEBUG
// Older SDKs do not include the addrinfo struct declaration, so we
// include a copy of it here.
struct qt_addrinfo
{
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
char *ai_canonname;
sockaddr *ai_addr;
qt_addrinfo *ai_next;
};
//### //###
#define QT_SOCKLEN_T int #define QT_SOCKLEN_T int
#ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h? #ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h?
#define NI_MAXHOST 1024 #define NI_MAXHOST 1024
#endif #endif
typedef int (__stdcall *getnameinfoProto)(const sockaddr *, QT_SOCKLEN_T, const char *, DWORD, const char *, DWORD, int);
typedef int (__stdcall *getaddrinfoProto)(const char *, const char *, const qt_addrinfo *, qt_addrinfo **);
typedef int (__stdcall *freeaddrinfoProto)(qt_addrinfo *);
static getnameinfoProto local_getnameinfo = 0;
static getaddrinfoProto local_getaddrinfo = 0;
static freeaddrinfoProto local_freeaddrinfo = 0;
static bool resolveLibraryInternal()
{
// Attempt to resolve getaddrinfo(); without it we'll have to fall
// back to gethostbyname(), which has no IPv6 support.
#if defined (Q_OS_WINRT)
local_getaddrinfo = (getaddrinfoProto) &getaddrinfo;
local_freeaddrinfo = (freeaddrinfoProto) &freeaddrinfo;
local_getnameinfo = (getnameinfoProto) getnameinfo;
#else
local_getaddrinfo = (getaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getaddrinfo");
local_freeaddrinfo = (freeaddrinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "freeaddrinfo");
local_getnameinfo = (getnameinfoProto) QSystemLibrary::resolve(QLatin1String("ws2_32"), "getnameinfo");
#endif
return true;
}
Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))
static void translateWSAError(int error, QHostInfo *results) static void translateWSAError(int error, QHostInfo *results)
{ {
switch (error) { switch (error) {
@ -114,21 +76,17 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
{ {
QSysInfo::machineHostName(); // this initializes ws2_32.dll QSysInfo::machineHostName(); // this initializes ws2_32.dll
// Load res_init on demand.
resolveLibrary();
QHostInfo results; QHostInfo results;
#if defined(QHOSTINFO_DEBUG) #if defined(QHOSTINFO_DEBUG)
qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)", qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)",
hostName.toLatin1().constData(), hostName.toLatin1().constData(),
(local_getaddrinfo && local_freeaddrinfo) ? "enabled" : "disabled"); (getaddrinfo && freeaddrinfo) ? "enabled" : "disabled");
#endif #endif
QHostAddress address; QHostAddress address;
if (address.setAddress(hostName)) { if (address.setAddress(hostName)) {
// Reverse lookup // Reverse lookup
if (local_getnameinfo) {
sockaddr_in sa4; sockaddr_in sa4;
sockaddr_in6 sa6; sockaddr_in6 sa6;
sockaddr *sa; sockaddr *sa;
@ -148,14 +106,8 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
} }
char hbuf[NI_MAXHOST]; char hbuf[NI_MAXHOST];
if (local_getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) if (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0)
results.setHostName(QString::fromLatin1(hbuf)); results.setHostName(QString::fromLatin1(hbuf));
} else {
unsigned long addr = inet_addr(hostName.toLatin1().constData());
struct hostent *ent = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
if (ent)
results.setHostName(QString::fromLatin1(ent->h_name));
}
if (results.hostName().isEmpty()) if (results.hostName().isEmpty())
results.setHostName(address.toString()); results.setHostName(address.toString());
@ -172,15 +124,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
return results; return results;
} }
if (local_getaddrinfo && local_freeaddrinfo) { addrinfo *res;
// Call getaddrinfo, and place all IPv4 addresses at the start int err = getaddrinfo(aceHostname.constData(), 0, 0, &res);
// and the IPv6 addresses at the end of the address list in
// results.
qt_addrinfo *res;
int err = local_getaddrinfo(aceHostname.constData(), 0, 0, &res);
if (err == 0) { if (err == 0) {
QList<QHostAddress> addresses; QList<QHostAddress> addresses;
for (qt_addrinfo *p = res; p != 0; p = p->ai_next) { for (addrinfo *p = res; p != 0; p = p->ai_next) {
switch (p->ai_family) { switch (p->ai_family) {
case AF_INET: { case AF_INET: {
QHostAddress addr; QHostAddress addr;
@ -202,35 +150,10 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
} }
} }
results.setAddresses(addresses); results.setAddresses(addresses);
local_freeaddrinfo(res); freeaddrinfo(res);
} else { } else {
translateWSAError(WSAGetLastError(), &results); translateWSAError(WSAGetLastError(), &results);
} }
} else {
// Fall back to gethostbyname, which only supports IPv4.
hostent *ent = gethostbyname(aceHostname.constData());
if (ent) {
char **p;
QList<QHostAddress> addresses;
switch (ent->h_addrtype) {
case AF_INET:
for (p = ent->h_addr_list; *p != 0; p++) {
long *ip4Addr = (long *) *p;
QHostAddress temp;
temp.setAddress(ntohl(*ip4Addr));
addresses << temp;
}
break;
default:
results.setError(QHostInfo::UnknownError);
results.setErrorString(tr("Unknown address type"));
break;
}
results.setAddresses(addresses);
} else {
translateWSAError(WSAGetLastError(), &results);
}
}
#if defined(QHOSTINFO_DEBUG) #if defined(QHOSTINFO_DEBUG)
if (results.error() != QHostInfo::NoError) { if (results.error() != QHostInfo::NoError) {

View File

@ -124,9 +124,7 @@ QT_BEGIN_NAMESPACE
\row \li Linux \li Supported \li Supported \li Supported \row \li Linux \li Supported \li Supported \li Supported
\row \li OS X \li Supported \li Supported \li Only for IPv6 \row \li OS X \li Supported \li Supported \li Only for IPv6
\row \li Other Unix supporting RFC 3542 \li Only for IPv6 \li Only for IPv6 \li Only for IPv6 \row \li Other Unix supporting RFC 3542 \li Only for IPv6 \li Only for IPv6 \li Only for IPv6
\row \li Windows XP and older \li Not supported \li Not supported \li Not supported \row \li Windows (desktop) \li Supported \li Supported \li Supported
\row \li Windows Vista & up \li Supported \li Supported \li Supported
\row \li Windows CE \li Not supported \li Not supported \li Not supported
\row \li Windows RT \li Not supported \li Not supported \li Not supported \row \li Windows RT \li Not supported \li Not supported \li Not supported
\endtable \endtable

View File

@ -56,6 +56,7 @@
// (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/) // (http://sourceforge.net/p/mingw-w64/mailman/message/32935366/)
#include <winsock2.h> #include <winsock2.h>
#include <ws2ipdef.h> #include <ws2ipdef.h>
#include <wincrypt.h>
#include <iphlpapi.h> #include <iphlpapi.h>
#include <ws2tcpip.h> #include <ws2tcpip.h>

View File

@ -174,16 +174,6 @@ static inline int qt_safe_ioctl(int sockfd, unsigned long request, T arg)
#endif #endif
} }
// VxWorks' headers do not specify any const modifiers
static inline in_addr_t qt_safe_inet_addr(const char *cp)
{
#ifdef Q_OS_VXWORKS
return ::inet_addr((char *) cp);
#else
return ::inet_addr(cp);
#endif
}
static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags) static inline int qt_safe_sendmsg(int sockfd, const struct msghdr *msg, int flags)
{ {
#ifdef MSG_NOSIGNAL #ifdef MSG_NOSIGNAL

View File

@ -454,9 +454,11 @@ QNetworkDatagram QUdpSocket::receiveDatagram(qint64 maxSize)
QAbstractSocketEngine::WantAll); QAbstractSocketEngine::WantAll);
d->hasPendingData = false; d->hasPendingData = false;
d->socketEngine->setReadNotificationEnabled(true); d->socketEngine->setReadNotificationEnabled(true);
if (readBytes < 0) if (readBytes < 0) {
d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString()); d->setErrorAndEmit(d->socketEngine->error(), d->socketEngine->errorString());
else if (readBytes != result.d->data.size()) readBytes = 0;
}
result.d->data.truncate(readBytes); result.d->data.truncate(readBytes);
return result; return result;
} }

View File

@ -92,7 +92,7 @@ EphemeralSecKeychain::EphemeralSecKeychain()
{ {
const auto uuid = QUuid::createUuid(); const auto uuid = QUuid::createUuid();
if (uuid.isNull()) { if (uuid.isNull()) {
qCWarning(lcSsl) << "Failed to create an unique keychain name"; qCWarning(lcSsl) << "Failed to create a unique keychain name";
return; return;
} }

View File

@ -666,7 +666,7 @@ static CTFontUIFontType fontTypeFromTheme(QPlatformTheme::Font f)
return kCTFontUIFontSystem; return kCTFontUIFontSystem;
case QPlatformTheme::TipLabelFont: case QPlatformTheme::TipLabelFont:
return kCTFontToolTipFontType; return kCTFontUIFontToolTip;
case QPlatformTheme::StatusBarFont: case QPlatformTheme::StatusBarFont:
return kCTFontUIFontSystem; return kCTFontUIFontSystem;

View File

@ -1980,12 +1980,6 @@ QFont QWindowsFontDatabase::systemDefaultFont()
// long deprecated; the message font of the NONCLIENTMETRICS structure obtained by // long deprecated; the message font of the NONCLIENTMETRICS structure obtained by
// SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see // SystemParametersInfo(SPI_GETNONCLIENTMETRICS) should be used instead (see
// QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger. // QWindowsTheme::refreshFonts(), typically "Segoe UI, 9pt"), which is larger.
// In single monitor setups, the point sizes revolve around 8 (depending on UI
// scale factor, but not proportional to it). However, in multi monitor setups,
// where the DPI of the primary monitor are smaller than those of the secondary,
// large bogus values are returned. Limit to 8.25 in that case.
if (GetSystemMetrics(SM_CMONITORS) > 1 && systemFont.pointSizeF() > 8.25)
systemFont.setPointSizeF(8.25);
#endif // Qt 5 #endif // Qt 5
qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont; qCDebug(lcQpaFonts) << __FUNCTION__ << systemFont;
return systemFont; return systemFont;

View File

@ -55,10 +55,10 @@
#if defined(Q_OS_WIN32) #if defined(Q_OS_WIN32)
// PMIB_TCPTABLE2 is only available since Vista // PMIB_TCPTABLE2 is only available since Vista
#if _WIN32_WINNT < 0x0600 #if _WIN32_WINNT < 0x0601
# undef _WIN32_WINNT # undef _WIN32_WINNT
# define _WIN32_WINNT 0x0600 # define _WIN32_WINNT 0x0601
#endif // _WIN32_WINNT < 0x0600 #endif // _WIN32_WINNT < 0x0601
#include "../platformdefs_win.h" #include "../platformdefs_win.h"
#include <iphlpapi.h> #include <iphlpapi.h>
#endif #endif

View File

@ -45,6 +45,7 @@
#include <winsock2.h> #include <winsock2.h>
#include <mswsock.h> #include <mswsock.h>
#undef interface #undef interface
#include <wincrypt.h>
#include <winioctl.h> #include <winioctl.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE

View File

@ -520,7 +520,7 @@ static inline int fromBase8(const char *s, const char *end)
{ {
int result = 0; int result = 0;
while (*s && s != end) { while (*s && s != end) {
if (*s <= '0' || *s >= '7') if (*s < '0' || *s > '7')
return 0; return 0;
result *= 8; result *= 8;
result += *s - '0'; result += *s - '0';

View File

@ -104,11 +104,11 @@ namespace QtAndroidAccessibility
static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId) static jintArray childIdListForAccessibleObject(JNIEnv *env, jobject /*thiz*/, jint objectId)
{ {
QAccessibleInterface *iface = interfaceFromId(objectId); QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface) { if (iface && iface->isValid()) {
jintArray jArray = env->NewIntArray(jsize(iface->childCount())); jintArray jArray = env->NewIntArray(jsize(iface->childCount()));
for (int i = 0; i < iface->childCount(); ++i) { for (int i = 0; i < iface->childCount(); ++i) {
QAccessibleInterface *child = iface->child(i); QAccessibleInterface *child = iface->child(i);
if (child) { if (child && child->isValid()) {
QAccessible::Id ifaceId = QAccessible::uniqueId(child); QAccessible::Id ifaceId = QAccessible::uniqueId(child);
jint jid = ifaceId; jint jid = ifaceId;
env->SetIntArrayRegion(jArray, i, 1, &jid); env->SetIntArrayRegion(jArray, i, 1, &jid);
@ -123,9 +123,9 @@ namespace QtAndroidAccessibility
static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) static jint parentId(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{ {
QAccessibleInterface *iface = interfaceFromId(objectId); QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface) { if (iface && iface->isValid()) {
QAccessibleInterface *parent = iface->parent(); QAccessibleInterface *parent = iface->parent();
if (parent) { if (parent && parent->isValid()) {
if (parent->role() == QAccessible::Application) if (parent->role() == QAccessible::Application)
return -1; return -1;
return QAccessible::uniqueId(parent); return QAccessible::uniqueId(parent);
@ -151,7 +151,7 @@ namespace QtAndroidAccessibility
static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y) static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y)
{ {
QAccessibleInterface *root = interfaceFromId(-1); QAccessibleInterface *root = interfaceFromId(-1);
if (root) { if (root && root->isValid()) {
QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window()); QPoint pos = QHighDpi::fromNativePixels(QPoint(int(x), int(y)), root->window());
QAccessibleInterface *child = root->childAt(pos.x(), pos.y()); QAccessibleInterface *child = root->childAt(pos.x(), pos.y());
@ -170,7 +170,7 @@ namespace QtAndroidAccessibility
{ {
// qDebug() << "A11Y: CLICK: " << objectId; // qDebug() << "A11Y: CLICK: " << objectId;
QAccessibleInterface *iface = interfaceFromId(objectId); QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->actionInterface()) { if (iface && iface->isValid() && iface->actionInterface()) {
if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction())) if (iface->actionInterface()->actionNames().contains(QAccessibleActionInterface::pressAction()))
iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction()); iface->actionInterface()->doAction(QAccessibleActionInterface::pressAction());
else else
@ -182,13 +182,17 @@ namespace QtAndroidAccessibility
static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) static jboolean scrollForward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{ {
QAccessibleInterface *iface = interfaceFromId(objectId); QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid())
return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction()); return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::increaseAction());
return false;
} }
static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId) static jboolean scrollBackward(JNIEnv */*env*/, jobject /*thiz*/, jint objectId)
{ {
QAccessibleInterface *iface = interfaceFromId(objectId); QAccessibleInterface *iface = interfaceFromId(objectId);
if (iface && iface->isValid())
return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction()); return QAccessibleBridgeUtils::performEffectiveAction(iface, QAccessibleActionInterface::decreaseAction());
return false;
} }

View File

@ -450,6 +450,17 @@ static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobj
static void *startMainMethod(void */*data*/) static void *startMainMethod(void */*data*/)
{ {
{
JNIEnv* env = nullptr;
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = "QtMainThread";
args.group = NULL;
JavaVM *vm = QtAndroidPrivate::javaVM();
if (vm != 0)
vm->AttachCurrentThread(&env, &args);
}
QVarLengthArray<const char *> params(m_applicationParams.size()); QVarLengthArray<const char *> params(m_applicationParams.size());
for (int i = 0; i < m_applicationParams.size(); i++) for (int i = 0; i < m_applicationParams.size(); i++)
params[i] = static_cast<const char *>(m_applicationParams[i].constData()); params[i] = static_cast<const char *>(m_applicationParams[i].constData());

View File

@ -1,6 +1,6 @@
TARGET = qcocoa TARGET = qcocoa
OBJECTIVE_SOURCES += main.mm \ SOURCES += main.mm \
qcocoaintegration.mm \ qcocoaintegration.mm \
qcocoascreen.mm \ qcocoascreen.mm \
qcocoatheme.mm \ qcocoatheme.mm \
@ -32,9 +32,8 @@ OBJECTIVE_SOURCES += main.mm \
qcocoasystemtrayicon.mm \ qcocoasystemtrayicon.mm \
qcocoaintrospection.mm \ qcocoaintrospection.mm \
qcocoakeymapper.mm \ qcocoakeymapper.mm \
qcocoamimetypes.mm qcocoamimetypes.mm \
messages.cpp
SOURCES += messages.cpp
HEADERS += qcocoaintegration.h \ HEADERS += qcocoaintegration.h \
qcocoascreen.h \ qcocoascreen.h \
@ -70,7 +69,7 @@ HEADERS += qcocoaintegration.h \
qcocoamimetypes.h qcocoamimetypes.h
qtConfig(opengl.*) { qtConfig(opengl.*) {
OBJECTIVE_SOURCES += qcocoaglcontext.mm SOURCES += qcocoaglcontext.mm
HEADERS += qcocoaglcontext.h HEADERS += qcocoaglcontext.h
} }
@ -89,7 +88,7 @@ CONFIG += no_app_extension_api_only
qtHaveModule(widgets) { qtHaveModule(widgets) {
QT_FOR_CONFIG += widgets QT_FOR_CONFIG += widgets
OBJECTIVE_SOURCES += \ SOURCES += \
qpaintengine_mac.mm \ qpaintengine_mac.mm \
qprintengine_mac.mm \ qprintengine_mac.mm \
qcocoaprintersupport.mm \ qcocoaprintersupport.mm \

View File

@ -92,7 +92,6 @@
QT_USE_NAMESPACE QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSMenu);
@class QT_MANGLE_NAMESPACE(QNSImageView); @class QT_MANGLE_NAMESPACE(QNSImageView);
@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate> @interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject <NSUserNotificationCenterDelegate>
@ -123,16 +122,8 @@ QT_USE_NAMESPACE
-(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton; -(void)mousePressed:(NSEvent *)mouseEvent button:(Qt::MouseButton)mouseButton;
@end @end
@interface QT_MANGLE_NAMESPACE(QNSMenu) : NSMenu <NSMenuDelegate> {
QPlatformMenu *qmenu;
}
-(QPlatformMenu*)menu;
-(id)initWithQMenu:(QPlatformMenu*)qmenu;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem); QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSStatusItem);
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView); QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSImageView);
QT_NAMESPACE_ALIAS_OBJC_CLASS(QNSMenu);
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QSystemTrayIconSys class QSystemTrayIconSys
@ -447,26 +438,4 @@ QT_END_NAMESPACE
@end @end
class QSystemTrayIconQMenu : public QPlatformMenu
{
public:
void doAboutToShow() { emit aboutToShow(); }
private:
QSystemTrayIconQMenu();
};
@implementation QNSMenu
-(id)initWithQMenu:(QPlatformMenu*)qm {
self = [super init];
if (self) {
self->qmenu = qm;
[self setDelegate:self];
}
return self;
}
-(QPlatformMenu*)menu {
return qmenu;
}
@end
#endif // QT_NO_SYSTEMTRAYICON #endif // QT_NO_SYSTEMTRAYICON

View File

@ -55,6 +55,7 @@
#include <QtGui/private/qguiapplication_p.h> #include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qcoregraphics_p.h> #include <QtGui/private/qcoregraphics_p.h>
#include <QtGui/qpainter.h> #include <QtGui/qpainter.h>
#include <QtGui/qtextformat.h>
#include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h> #include <QtFontDatabaseSupport/private/qcoretextfontdatabase_p.h>
#include <QtThemeSupport/private/qabstractfileiconengine_p.h> #include <QtThemeSupport/private/qabstractfileiconengine_p.h>
#include <qpa/qplatformdialoghelper.h> #include <qpa/qplatformdialoghelper.h>
@ -344,6 +345,8 @@ QVariant QCocoaTheme::themeHint(ThemeHint hint) const
return QVariant(QChar(0x2022)); return QVariant(QChar(0x2022));
case QPlatformTheme::UiEffects: case QPlatformTheme::UiEffects:
return QVariant(int(HoverEffect)); return QVariant(int(HoverEffect));
case QPlatformTheme::SpellCheckUnderlineStyle:
return QVariant(int(QTextCharFormat::DotLine));
default: default:
break; break;
} }

View File

@ -262,7 +262,7 @@ public: // for QNSView
bool m_hasModalSession; bool m_hasModalSession;
bool m_frameStrutEventsEnabled; bool m_frameStrutEventsEnabled;
bool m_isExposed; QRect m_exposedRect;
int m_registerTouchCount; int m_registerTouchCount;
bool m_resizableTransientParent; bool m_resizableTransientParent;

View File

@ -150,7 +150,6 @@ QCocoaWindow::QCocoaWindow(QWindow *win, WId nativeHandle)
, m_needsInvalidateShadow(false) , m_needsInvalidateShadow(false)
, m_hasModalSession(false) , m_hasModalSession(false)
, m_frameStrutEventsEnabled(false) , m_frameStrutEventsEnabled(false)
, m_isExposed(false)
, m_registerTouchCount(0) , m_registerTouchCount(0)
, m_resizableTransientParent(false) , m_resizableTransientParent(false)
, m_alertRequest(NoAlertRequest) , m_alertRequest(NoAlertRequest)
@ -692,7 +691,7 @@ void QCocoaWindow::lower()
bool QCocoaWindow::isExposed() const bool QCocoaWindow::isExposed() const
{ {
return m_isExposed; return !m_exposedRect.isEmpty();
} }
bool QCocoaWindow::isOpaque() const bool QCocoaWindow::isOpaque() const
@ -1120,7 +1119,7 @@ void QCocoaWindow::handleGeometryChange()
void QCocoaWindow::handleExposeEvent(const QRegion &region) void QCocoaWindow::handleExposeEvent(const QRegion &region)
{ {
const bool wasExposed = isExposed(); const QRect previouslyExposedRect = m_exposedRect;
// Ideally we'd implement isExposed() in terms of these properties, // Ideally we'd implement isExposed() in terms of these properties,
// plus the occlusionState of the NSWindow, and let the expose event // plus the occlusionState of the NSWindow, and let the expose event
@ -1133,27 +1132,29 @@ void QCocoaWindow::handleExposeEvent(const QRegion &region)
// a window being obscured is an empty region, and in the case of // a window being obscured is an empty region, and in the case of
// a drawRect call is a non-null region, even if occlusionState // a drawRect call is a non-null region, even if occlusionState
// is still hidden. This ensures the window is prepared for display. // is still hidden. This ensures the window is prepared for display.
m_isExposed = m_view.window.visible if (m_view.window.visible && m_view.window.screen
&& m_view.window.screen && !geometry().size().isEmpty() && !region.isEmpty()
&& !geometry().size().isEmpty() && !m_view.hiddenOrHasHiddenAncestor) {
&& !region.isEmpty() m_exposedRect = region.boundingRect();
&& !m_view.hiddenOrHasHiddenAncestor; } else {
m_exposedRect = QRect();
}
QWindowPrivate *windowPrivate = qt_window_private(window()); QWindowPrivate *windowPrivate = qt_window_private(window());
if (windowPrivate->updateRequestPending) { if (windowPrivate->updateRequestPending) {
// We can only deliver update request events when the window is exposed, // We can only deliver update request events when the window is exposed,
// and we also have to make sure we deliver the first expose event after // and we also have to make sure we deliver any change to the exposed
// becoming exposed as a real expose event, otherwise the exposed state // rect as a real expose event (including going from non-exposed to
// of the QWindow is never updated. // exposed). FIXME: Should this logic live in QGuiApplication?
// FIXME: Should this logic live in QGuiApplication? if (isExposed() && m_exposedRect == previouslyExposedRect) {
if (wasExposed && m_isExposed) {
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request"; qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "as update request";
windowPrivate->deliverUpdateRequest(); windowPrivate->deliverUpdateRequest();
return; return;
} else {
// Since updateRequestPending is still set, we will issue a deferred setNeedsDisplay
// from drawRect and get back into this code on the next display cycle, delivering
// the pending update request.
} }
// FIXME: Should we re-trigger setNeedsDisplay in case of !wasExposed && m_isExposed?
// Or possibly send the expose event first, and then the update request?
} }
qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed(); qCDebug(lcQpaCocoaWindow) << "QCocoaWindow::handleExposeEvent" << window() << region << "isExposed" << isExposed();
@ -1669,6 +1670,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
if (!m_drawContentBorderGradient) { if (!m_drawContentBorderGradient) {
window.styleMask = window.styleMask & ~NSTexturedBackgroundWindowMask; window.styleMask = window.styleMask & ~NSTexturedBackgroundWindowMask;
[window.contentView.superview setNeedsDisplay:YES]; [window.contentView.superview setNeedsDisplay:YES];
window.titlebarAppearsTransparent = NO;
return; return;
} }
@ -1693,6 +1695,7 @@ void QCocoaWindow::applyContentBorderThickness(NSWindow *window)
int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness; int effectiveBottomContentBorderThickness = m_bottomContentBorderThickness;
[window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask]; [window setStyleMask:[window styleMask] | NSTexturedBackgroundWindowMask];
window.titlebarAppearsTransparent = YES;
[window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge]; [window setContentBorderThickness:effectiveTopContentBorderThickness forEdge:NSMaxYEdge];
[window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge]; [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];

View File

@ -324,12 +324,13 @@ Q_LOGGING_CATEGORY(lcQpaTablet, "qt.qpa.input.tablet")
m_platformWindow->handleExposeEvent(exposedRegion); m_platformWindow->handleExposeEvent(exposedRegion);
// A call to QWindow::requestUpdate was issued during the expose event, but
// AppKit will reset the needsDisplay state of the view after completing the
// current display cycle, so we need to defer the request to redisplay.
// FIXME: Perhaps this should be a trigger to enable CADisplayLink?
if (qt_window_private(m_platformWindow->window())->updateRequestPending) { if (qt_window_private(m_platformWindow->window())->updateRequestPending) {
qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:] deferring setNeedsDisplay"; // A call to QWindow::requestUpdate was issued during the expose event, or we
// had to deliver a real expose event and still need to deliver the update.
// But AppKit will reset the needsDisplay state of the view after completing
// the current display cycle, so we need to defer the request to redisplay.
// FIXME: Perhaps this should be a trigger to enable CADisplayLink?
qCDebug(lcQpaCocoaWindow) << "[QNSView drawRect:] issuing deferred setNeedsDisplay due to pending update request";
dispatch_async(dispatch_get_main_queue (), ^{ dispatch_async(dispatch_get_main_queue (), ^{
[self setNeedsDisplay:YES]; [self setNeedsDisplay:YES];
}); });

View File

@ -2,9 +2,10 @@ TARGET = qdirect2d
QT += \ QT += \
core-private gui-private \ core-private gui-private \
eventdispatcher_support-private accessibility_support-private \ eventdispatcher_support-private \
fontdatabase_support-private theme_support-private fontdatabase_support-private theme_support-private
qtConfig(accessibility): QT += accessibility_support-private
qtConfig(vulkan): QT += vulkan_support-private qtConfig(vulkan): QT += vulkan_support-private
LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32 LIBS += -ldwmapi -ld2d1 -ld3d11 -ldwrite -lVersion -lgdi32

View File

@ -47,7 +47,9 @@
#include "qwindowsmenu.h" #include "qwindowsmenu.h"
#include "qwindowsmime.h" #include "qwindowsmime.h"
#include "qwindowsinputcontext.h" #include "qwindowsinputcontext.h"
#if QT_CONFIG(tabletevent)
# include "qwindowstabletsupport.h" # include "qwindowstabletsupport.h"
#endif
#include "qwindowstheme.h" #include "qwindowstheme.h"
#include <private/qguiapplication_p.h> #include <private/qguiapplication_p.h>
#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_ACCESSIBILITY

View File

@ -39,7 +39,9 @@
#define QT_NO_URL_CAST_FROM_STRING 1 #define QT_NO_URL_CAST_FROM_STRING 1
#define _WIN32_WINNT 0x0600 #ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601
#endif
#include "qwindowscombase.h" #include "qwindowscombase.h"
#include "qwindowsdialoghelpers.h" #include "qwindowsdialoghelpers.h"

View File

@ -37,13 +37,6 @@
** **
****************************************************************************/ ****************************************************************************/
#if defined(WINVER) && WINVER < 0x0601
# undef WINVER
#endif
#if !defined(WINVER)
# define WINVER 0x0601 // Enable touch functions for MinGW
#endif
#include "qwindowsmousehandler.h" #include "qwindowsmousehandler.h"
#include "qwindowskeymapper.h" #include "qwindowskeymapper.h"
#include "qwindowscontext.h" #include "qwindowscontext.h"

View File

@ -352,16 +352,26 @@ bool QWindowsTabletSupport::translateTabletProximityEvent(WPARAM /* wParam */, L
{ {
PACKET proximityBuffer[1]; // we are only interested in the first packet in this case PACKET proximityBuffer[1]; // we are only interested in the first packet in this case
const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer); const int totalPacks = QWindowsTabletSupport::m_winTab32DLL.wTPacketsGet(m_context, 1, proximityBuffer);
if (!totalPacks)
return false;
if (!LOWORD(lParam)) { if (!LOWORD(lParam)) {
qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice; qCDebug(lcQpaTablet) << "leave proximity for device #" << m_currentDevice;
if (totalPacks > 0) {
QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime, QWindowSystemInterface::handleTabletLeaveProximityEvent(proximityBuffer[0].pkTime,
m_devices.at(m_currentDevice).currentDevice, m_devices.at(m_currentDevice).currentDevice,
m_devices.at(m_currentDevice).currentPointerType, m_devices.at(m_currentDevice).currentPointerType,
m_devices.at(m_currentDevice).uniqueId); m_devices.at(m_currentDevice).uniqueId);
} else {
QWindowSystemInterface::handleTabletLeaveProximityEvent(m_devices.at(m_currentDevice).currentDevice,
m_devices.at(m_currentDevice).currentPointerType,
m_devices.at(m_currentDevice).uniqueId);
}
return true; return true;
} }
if (!totalPacks)
return false;
const UINT currentCursor = proximityBuffer[0].pkCursor; const UINT currentCursor = proximityBuffer[0].pkCursor;
UINT physicalCursorId; UINT physicalCursorId;
QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId); QWindowsTabletSupport::m_winTab32DLL.wTInfo(WTI_CURSORS + currentCursor, CSR_PHYSID, &physicalCursorId);

Some files were not shown because too many files have changed in this diff Show More