Merge "Merge remote-tracking branch 'origin/5.12' into 5.13"

This commit is contained in:
Qt Forward Merge Bot 2019-07-13 01:00:21 +02:00
commit a837ec15fe
10 changed files with 125 additions and 57 deletions

View File

@ -1512,9 +1512,9 @@ static void qDefaultMsgHandler(QtMsgType type, const char *buf);
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf);
// pointer to QtMsgHandler debug handler (without context)
static QBasicAtomicPointer<void (QtMsgType, const char*)> msgHandler = Q_BASIC_ATOMIC_INITIALIZER(qDefaultMsgHandler);
static QBasicAtomicPointer<void (QtMsgType, const char*)> msgHandler = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
// pointer to QtMessageHandler debug handler (with context)
static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext &, const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(qDefaultMessageHandler);
static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext &, const QString &)> messageHandler = Q_BASIC_ATOMIC_INITIALIZER(nullptr);
// ------------------------ Alternate logging sinks -------------------------
@ -1826,14 +1826,17 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
// prevent recursion in case the message handler generates messages
// itself, e.g. by using Qt API
if (grabMessageHandler()) {
struct Ungrabber {
~Ungrabber() { ungrabMessageHandler(); }
} ungrabber;
auto oldStyle = msgHandler.loadAcquire();
auto newStye = messageHandler.loadAcquire();
// prefer new message handler over the old one
if (msgHandler.load() == qDefaultMsgHandler
|| messageHandler.load() != qDefaultMessageHandler) {
(*messageHandler.load())(msgType, context, message);
if (newStye || !oldStyle) {
(newStye ? newStye : qDefaultMessageHandler)(msgType, context, message);
} else {
(*msgHandler.load())(msgType, message.toLocal8Bit().constData());
(oldStyle ? oldStyle : qDefaultMsgHandler)(msgType, message.toLocal8Bit().constData());
}
ungrabMessageHandler();
} else {
fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
}
@ -2084,18 +2087,20 @@ void qErrnoWarning(int code, const char *msg, ...)
QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
{
if (!h)
h = qDefaultMessageHandler;
//set 'h' and return old message handler
return messageHandler.fetchAndStoreRelaxed(h);
const auto old = messageHandler.fetchAndStoreOrdered(h);
if (old)
return old;
else
return qDefaultMessageHandler;
}
QtMsgHandler qInstallMsgHandler(QtMsgHandler h)
{
if (!h)
h = qDefaultMsgHandler;
//set 'h' and return old message handler
return msgHandler.fetchAndStoreRelaxed(h);
const auto old = msgHandler.fetchAndStoreOrdered(h);
if (old)
return old;
else
return qDefaultMsgHandler;
}
void qSetMessagePattern(const QString &pattern)

View File

@ -40,13 +40,54 @@
#include "qplatformdefs.h"
#include "qfilesystemiterator_p.h"
#if QT_CONFIG(textcodec)
# include <qtextcodec.h>
# include <private/qutfcodec_p.h>
#endif
#ifndef QT_NO_FILESYSTEMITERATOR
#include <memory>
#include <stdlib.h>
#include <errno.h>
QT_BEGIN_NAMESPACE
static bool checkNameDecodable(const char *d_name, qsizetype len)
{
// This function is called in a loop from advance() below, but the loop is
// usually run only once.
#if QT_CONFIG(textcodec)
// We identify the codecs by their RFC 2978 MIBenum values. In this
// function:
// 3 US-ASCII (ANSI X3.4-1986)
// 4 Latin1 (ISO-8859-1)
// 106 UTF-8
QTextCodec *codec = QTextCodec::codecForLocale();
# ifdef QT_LOCALE_IS_UTF8
int mibEnum = 106;
# else
int mibEnum = codec->mibEnum();
# endif
if (Q_LIKELY(mibEnum == 106)) // UTF-8
return QUtf8::isValidUtf8(d_name, len).isValidUtf8;
if (mibEnum == 3) // US-ASCII
return QtPrivate::isAscii(QLatin1String(d_name, len));
if (mibEnum == 4) // Latin 1
return true;
// fall back to generic QTextCodec
QTextCodec::ConverterState cs(QTextCodec::IgnoreHeader);
codec->toUnicode(d_name, len, &cs);
return cs.invalidChars == 0 && cs.remainingChars == 0;
#else
// if we have no text codecs, then QString::fromLocal8Bit is fromLatin1
return true;
#endif
}
QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &entry, QDir::Filters filters,
const QStringList &nameFilters, QDirIterator::IteratorFlags flags)
: nativePath(entry.nativeFilePath())
@ -81,9 +122,9 @@ bool QFileSystemIterator::advance(QFileSystemEntry &fileEntry, QFileSystemMetaDa
dirEntry = QT_READDIR(dir);
if (dirEntry) {
// process entries with correct UTF-8 names only
if (QFile::encodeName(QFile::decodeName(dirEntry->d_name)) == dirEntry->d_name) {
fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name), QFileSystemEntry::FromNativePath());
qsizetype len = strlen(dirEntry->d_name);
if (checkNameDecodable(dirEntry->d_name, len)) {
fileEntry = QFileSystemEntry(nativePath + QByteArray(dirEntry->d_name, len), QFileSystemEntry::FromNativePath());
metaData.fillFromDirEnt(*dirEntry);
return true;
}

View File

@ -197,6 +197,7 @@ bool QSaveFile::open(OpenMode mode)
return false;
}
unsetError();
d->writeError = QFileDevice::NoError;
if ((mode & (ReadOnly | WriteOnly)) == 0) {
qWarning("QSaveFile::open: Open mode not specified");
return false;

View File

@ -264,7 +264,6 @@ bool QCocoaSystemTrayIcon::supportsMessages() const
void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &message,
const QIcon& icon, MessageIcon, int)
{
Q_UNUSED(icon);
if (!m_sys)
return;
@ -272,6 +271,12 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
if (!icon.isNull()) {
auto *nsimage = qt_mac_create_nsimage(icon);
[nsimage setTemplate:icon.isMask()];
notification.contentImage = [nsimage autorelease];
}
[[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
}
QT_END_NAMESPACE

View File

@ -522,16 +522,16 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
if (mode == property(PPK_Duplex).toInt() || !d->m_printDevice->supportedDuplexModes().contains(mode))
break;
switch (mode) {
case QPrinter::DuplexNone:
case QPrint::DuplexNone:
PMSetDuplex(d->settings(), kPMDuplexNone);
break;
case QPrinter::DuplexAuto:
case QPrint::DuplexAuto:
PMSetDuplex(d->settings(), d->m_pageLayout.orientation() == QPageLayout::Landscape ? kPMDuplexTumble : kPMDuplexNoTumble);
break;
case QPrinter::DuplexLongSide:
case QPrint::DuplexLongSide:
PMSetDuplex(d->settings(), kPMDuplexNoTumble);
break;
case QPrinter::DuplexShortSide:
case QPrint::DuplexShortSide:
PMSetDuplex(d->settings(), kPMDuplexTumble);
break;
default:

View File

@ -1965,7 +1965,7 @@ bool QApplication::event(QEvent *e)
*/
// ### FIXME: topLevelWindows does not contain QWidgets without a parent
// until create_sys is called. So we have to override the
// until QWidgetPrivate::create is called. So we have to override the
// QGuiApplication::notifyLayoutDirectionChange
// to do the right thing.
void QApplicationPrivate::notifyLayoutDirectionChange()

View File

@ -1190,7 +1190,7 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
q->setAttribute(Qt::WA_ContentsMarginsRespectsSafeArea);
q->setAttribute(Qt::WA_WState_Hidden);
//give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later
//give potential windows a bigger "pre-initial" size; create() will give them a new size later
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,640,480);
focus_next = focus_prev = q;
@ -1255,27 +1255,19 @@ void QWidgetPrivate::createRecursively()
/*!
Creates a new widget window.
The parameter \a window is ignored in Qt 5. Please use
QWindow::fromWinId() to create a QWindow wrapping a foreign
window and pass it to QWidget::createWindowContainer() instead.
Initializes the window (sets the geometry etc.) if \a
initializeWindow is true. If \a initializeWindow is false, no
initialization is performed. This parameter only makes sense if \a
window is a valid window.
Destroys the old window if \a destroyOldWindow is true. If \a
destroyOldWindow is false, you are responsible for destroying the
window yourself (using platform native code).
The QWidget constructor calls create(0,true,true) to create a
window for this widget.
The parameters \a window, \a initializeWindow, and \a destroyOldWindow
are ignored in Qt 5. Please use QWindow::fromWinId() to create a
QWindow wrapping a foreign window and pass it to
QWidget::createWindowContainer() instead.
\sa createWindowContainer(), QWindow::fromWinId()
*/
void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
{
Q_UNUSED(initializeWindow);
Q_UNUSED(destroyOldWindow);
Q_D(QWidget);
if (Q_UNLIKELY(window))
qWarning("QWidget::create(): Parameter 'window' does not have any effect.");
@ -1335,7 +1327,7 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
d->updateIsOpaque();
setAttribute(Qt::WA_WState_Created); // set created flag
d->create_sys(window, initializeWindow, destroyOldWindow);
d->create();
// a real toplevel window needs a backing store
if (isWindow() && windowType() != Qt::Desktop) {
@ -1404,14 +1396,10 @@ void q_createNativeChildrenAndSetParent(const QWidget *parentWidget)
}
void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
void QWidgetPrivate::create()
{
Q_Q(QWidget);
Q_UNUSED(window);
Q_UNUSED(initializeWindow);
Q_UNUSED(destroyOldWindow);
if (!q->testAttribute(Qt::WA_NativeWindow) && !q->isWindow())
return; // we only care about real toplevels
@ -9384,12 +9372,6 @@ bool QWidget::event(QEvent *event)
d->renderToTextureReallyDirty = 1;
#endif
break;
case QEvent::PlatformSurface: {
auto surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed)
d->setWinId(0);
break;
}
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@ -11348,7 +11330,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
// windowModality property and then reshown.
}
if (testAttribute(Qt::WA_WState_Created)) {
// don't call setModal_sys() before create_sys()
// don't call setModal_sys() before create()
d->setModal_sys();
}
break;

View File

@ -352,7 +352,7 @@ public:
void update(T t);
void init(QWidget *desktopWidget, Qt::WindowFlags f);
void create_sys(WId window, bool initializeWindow, bool destroyOldWindow);
void create();
void createRecursively();
void createWinId();

View File

@ -72,6 +72,7 @@ public slots:
private slots:
void transactionalWrite();
void retryTransactionalWrite();
void textStreamManualFlush();
void textStreamAutoFlush();
void saveTwice();
@ -129,6 +130,39 @@ void tst_QSaveFile::transactionalWrite()
QCOMPARE(QFile::permissions(targetFile), QFile::permissions(otherFile));
}
// QTBUG-77007: Simulate the case of an application with a loop prompting
// to retry saving on failure. Create a read-only file first (Unix only)
void tst_QSaveFile::retryTransactionalWrite()
{
#ifndef Q_OS_UNIX
QSKIP("This test is Unix only");
#endif
QTemporaryDir dir;
QVERIFY2(dir.isValid(), qPrintable(dir.errorString()));
QString targetFile = dir.path() + QLatin1String("/outfile");
const QString readOnlyName = targetFile + QLatin1String(".ro");
{
QFile readOnlyFile(readOnlyName);
QVERIFY2(readOnlyFile.open(QIODevice::WriteOnly), msgCannotOpen(readOnlyFile).constData());
readOnlyFile.write("Hello");
readOnlyFile.close();
auto permissions = readOnlyFile.permissions();
permissions &= ~(QFileDevice::WriteOwner | QFileDevice::WriteGroup | QFileDevice::WriteUser);
QVERIFY(readOnlyFile.setPermissions(permissions));
}
QSaveFile file(readOnlyName);
QVERIFY(!file.open(QIODevice::WriteOnly));
file.setFileName(targetFile);
QVERIFY2(file.open(QIODevice::WriteOnly), msgCannotOpen(file).constData());
QVERIFY(file.isOpen());
QCOMPARE(file.write("Hello"), Q_INT64_C(5));
QCOMPARE(file.error(), QFile::NoError);
QVERIFY(file.commit());
}
void tst_QSaveFile::saveTwice()
{
// Check that we can reuse a QSaveFile object

View File

@ -6141,7 +6141,7 @@ void tst_QWidget::minAndMaxSizeWithX11BypassWindowManagerHint()
{
if (m_platform != QStringLiteral("xcb"))
QSKIP("This test is for X11 only.");
// Same size as in QWidget::create_sys().
// Same size as in QWidgetPrivate::create.
const QSize desktopSize = QApplication::desktop()->size();
const QSize originalSize(desktopSize.width() / 2, desktopSize.height() * 4 / 10);
@ -9416,7 +9416,7 @@ void tst_QWidget::initialPosForDontShowOnScreenWidgets()
const QPoint expectedPos(0, 0);
QWidget widget;
widget.setAttribute(Qt::WA_DontShowOnScreen);
widget.winId(); // Make sure create_sys is called.
widget.winId(); // Make sure QWidgetPrivate::create is called.
QCOMPARE(widget.pos(), expectedPos);
QCOMPARE(widget.geometry().topLeft(), expectedPos);
}
@ -9426,7 +9426,7 @@ void tst_QWidget::initialPosForDontShowOnScreenWidgets()
QWidget widget;
widget.setAttribute(Qt::WA_DontShowOnScreen);
widget.move(expectedPos);
widget.winId(); // Make sure create_sys is called.
widget.winId(); // Make sure QWidgetPrivate::create is called.
QCOMPARE(widget.pos(), expectedPos);
QCOMPARE(widget.geometry().topLeft(), expectedPos);
}