Merge "Merge remote-tracking branch 'origin/5.12' into 5.13"
This commit is contained in:
commit
a837ec15fe
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user