summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/global/qglobal.cpp11
-rw-r--r--src/corelib/global/qglobal.h4
-rw-r--r--src/corelib/io/qdatastream.h5
-rw-r--r--src/corelib/io/qdebug.cpp27
-rw-r--r--src/corelib/io/qdebug.h25
-rw-r--r--src/corelib/io/qfiledevice.cpp2
-rw-r--r--src/corelib/io/qprocess.cpp6
-rw-r--r--src/corelib/io/qwindowspipereader.cpp8
-rw-r--r--src/corelib/io/qwindowspipereader_p.h4
-rw-r--r--src/corelib/kernel/qcoreevent.cpp2
-rw-r--r--src/corelib/kernel/qcoreevent.h2
-rw-r--r--src/corelib/kernel/qjni.cpp10
-rw-r--r--src/corelib/kernel/qjni_p.h8
-rw-r--r--src/corelib/kernel/qjnihelpers.cpp39
-rw-r--r--src/corelib/kernel/qjnihelpers_p.h13
-rw-r--r--src/corelib/plugin/qpluginloader.cpp26
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp51
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h4
-rw-r--r--src/corelib/tools/qcommandlineoption.cpp30
-rw-r--r--src/corelib/tools/qcommandlineoption.h3
-rw-r--r--src/corelib/tools/qcommandlineparser.cpp49
-rw-r--r--src/corelib/tools/qcommandlineparser.h6
-rw-r--r--src/corelib/tools/qringbuffer_p.h62
-rw-r--r--src/corelib/tools/qstring.cpp175
-rw-r--r--src/corelib/tools/qvector.h1
-rw-r--r--src/dbus/qdbusintegrator.cpp3
-rw-r--r--src/dbus/qdbusmessage.cpp30
-rw-r--r--src/dbus/qdbusmessage.h2
-rw-r--r--src/gui/kernel/qscreen.cpp38
-rw-r--r--src/gui/kernel/qscreen.h7
-rw-r--r--src/gui/kernel/qwindow.cpp39
-rw-r--r--src/gui/kernel/qwindow.h7
-rw-r--r--src/gui/kernel/qwindowsysteminterface.cpp1
-rw-r--r--src/gui/painting/painting.pri1
-rw-r--r--src/gui/painting/qcolor.cpp88
-rw-r--r--src/gui/painting/qcolor.h8
-rw-r--r--src/gui/painting/qrgba64.h195
-rw-r--r--src/gui/painting/qrgba64.qdoc241
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp53
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h1
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp14
-rw-r--r--src/network/access/qhttpnetworkreply.cpp30
-rw-r--r--src/network/access/qhttpnetworkreply_p.h10
-rw-r--r--src/network/access/qhttpnetworkrequest.cpp24
-rw-r--r--src/network/access/qhttpnetworkrequest_p.h8
-rw-r--r--src/network/access/qhttpthreaddelegate.cpp3
-rw-r--r--src/network/access/qhttpthreaddelegate_p.h2
-rw-r--r--src/network/access/qnetworkreply.cpp32
-rw-r--r--src/network/access/qnetworkreply.h3
-rw-r--r--src/network/access/qnetworkreply_p.h1
-rw-r--r--src/network/access/qnetworkreplyhttpimpl.cpp193
-rw-r--r--src/network/access/qnetworkreplyhttpimpl_p.h13
-rw-r--r--src/network/access/qnetworkreplyimpl.cpp12
-rw-r--r--src/network/access/qnetworkrequest.cpp44
-rw-r--r--src/network/access/qnetworkrequest.h5
-rw-r--r--src/network/socket/qabstractsocket.cpp8
-rw-r--r--src/platformheaders/xcbfunctions/qxcbfunctionshelper.h84
-rw-r--r--src/platformheaders/xcbfunctions/qxcbintegrationfunctions.h54
-rw-r--r--src/platformheaders/xcbfunctions/qxcbwindowfunctions.h36
-rw-r--r--src/platformheaders/xcbfunctions/xcbfunctions.pri4
-rw-r--r--src/platformsupport/linuxaccessibility/atspiadaptor.cpp126
-rw-r--r--src/platformsupport/linuxaccessibility/dbusconnection.cpp26
-rw-r--r--src/platformsupport/linuxaccessibility/dbusconnection_p.h1
-rw-r--r--src/plugins/platforms/android/androidjnimain.cpp5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm10
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm7
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm6
-rw-r--r--src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp10
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp21
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.cpp116
-rw-r--r--src/plugins/platforms/xcb/qxcbnativeinterface.h7
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp45
-rw-r--r--src/plugins/platforms/xcb/qxcbsystemtraytracker.h4
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp63
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h12
-rw-r--r--src/src.pro2
-rw-r--r--src/testlib/qtestblacklist.cpp59
-rw-r--r--src/tools/qdoc/config.cpp10
-rw-r--r--src/tools/qdoc/helpprojectwriter.cpp32
-rw-r--r--src/tools/qdoc/helpprojectwriter.h2
-rw-r--r--src/tools/qdoc/main.cpp4
-rw-r--r--src/widgets/accessible/qaccessiblewidgets.cpp57
-rw-r--r--src/widgets/dialogs/dialogs.pri1
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp132
-rw-r--r--src/widgets/dialogs/qcolordialog.h1
-rw-r--r--src/widgets/dialogs/qcolordialog_p.h179
-rw-r--r--src/widgets/kernel/qwidget.cpp84
-rw-r--r--src/widgets/kernel/qwidget.h9
-rw-r--r--src/widgets/util/qsystemtrayicon_x11.cpp32
-rw-r--r--tests/auto/corelib/io/qdebug/tst_qdebug.cpp34
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+haiku/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+haiku/test20
-rw-r--r--tests/auto/corelib/io/qfileselector/platforms/+unix/+haiku/test0
-rw-r--r--tests/auto/corelib/io/qfileselector/qfileselector.qrc3
-rw-r--r--tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp2
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp3
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp15
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp6
-rw-r--r--tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp37
-rw-r--r--tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp42
-rw-r--r--tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp45
-rw-r--r--tests/auto/gui/painting/qcolor/tst_qcolor.cpp85
-rw-r--r--tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp158
-rw-r--r--tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp53
-rw-r--r--tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp46
-rw-r--r--tests/auto/other/qaccessibility/tst_qaccessibility.cpp23
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp15
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h1
-rw-r--r--tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm341
-rw-r--r--tests/benchmarks/corelib/tools/qringbuffer/main.cpp4
-rw-r--r--tests/manual/qscreen/propertywatcher.cpp2
115 files changed, 3164 insertions, 693 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 7913af3103..abd9f4f593 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -2813,12 +2813,15 @@ QString QSysInfo::prettyProductName()
\macro void Q_CHECK_PTR(void *pointer)
\relates <QtGlobal>
- If \a pointer is 0, prints a warning message containing the source
+ If \a pointer is 0, prints a message containing the source
code's file name and line number, saying that the program ran out
- of memory.
+ of memory and aborts program execution. It throws \c std::bad_alloc instead
+ if exceptions are enabled.
- Q_CHECK_PTR does nothing if \c QT_NO_DEBUG was defined during
- compilation.
+ Q_CHECK_PTR does nothing if \c QT_NO_DEBUG and \c QT_NO_EXCEPTIONS were
+ defined during compilation. Therefore you must not use Q_CHECK_PTR to check
+ for successful memory allocations because the check will be disabled in
+ some cases.
Example:
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 27a3bf7c3d..c4e2f7609c 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -41,11 +41,11 @@
#include <stddef.h>
-#define QT_VERSION_STR "5.5.0"
+#define QT_VERSION_STR "5.6.0"
/*
QT_VERSION is (major << 16) + (minor << 8) + patch.
*/
-#define QT_VERSION 0x050500
+#define QT_VERSION 0x050600
/*
can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0))
*/
diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h
index 436bf8dd57..b87dbe4784 100644
--- a/src/corelib/io/qdatastream.h
+++ b/src/corelib/io/qdatastream.h
@@ -83,10 +83,11 @@ public:
Qt_5_3 = Qt_5_2,
Qt_5_4 = 16,
Qt_5_5 = Qt_5_4,
-#if QT_VERSION >= 0x050600
+ Qt_5_6 = Qt_5_5,
+#if QT_VERSION >= 0x050700
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
- Qt_DefaultCompiledVersion = Qt_5_5
+ Qt_DefaultCompiledVersion = Qt_5_6
};
enum ByteOrder {
diff --git a/src/corelib/io/qdebug.cpp b/src/corelib/io/qdebug.cpp
index 357d63137c..8676fe0259 100644
--- a/src/corelib/io/qdebug.cpp
+++ b/src/corelib/io/qdebug.cpp
@@ -334,6 +334,7 @@ QDebug &QDebug::resetFormat()
stream->space = true;
if (stream->context.version > 1)
stream->flags = 0;
+ stream->setVerbosity(Stream::defaultVerbosity);
return *this;
}
@@ -424,6 +425,32 @@ QDebug &QDebug::resetFormat()
*/
/*!
+ \fn int QDebug::verbosity() const
+ \since 5.6
+
+ Returns the verbosity of the debug stream.
+
+ Streaming operators can check the value to decide whether
+ verbose output is desired and print more information depending on the
+ level. Higher values indicate that more information is desired.
+
+ The allowed range is from 0 to 7. The default value is 2.
+
+ \sa setVerbosity()
+*/
+
+/*!
+ \fn void QDebug::setVerbosity(int verbosityLevel)
+ \since 5.6
+
+ Sets the verbosity of the stream to \a verbosityLevel.
+
+ The allowed range is from 0 to 7. The default value is 2.
+
+ \sa verbosity()
+*/
+
+/*!
\fn QDebug &QDebug::operator<<(QChar t)
Writes the character, \a t, to the stream and returns a reference to the
diff --git a/src/corelib/io/qdebug.h b/src/corelib/io/qdebug.h
index 89e2bb0afd..354c0e1392 100644
--- a/src/corelib/io/qdebug.h
+++ b/src/corelib/io/qdebug.h
@@ -53,9 +53,14 @@ class Q_CORE_EXPORT QDebug
friend class QMessageLogger;
friend class QDebugStateSaverPrivate;
struct Stream {
- Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg), space(true), message_output(false), flags(0) {}
- Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg), space(true), message_output(false), flags(0) {}
- Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t), space(true), message_output(true), flags(0) {}
+ enum { defaultVerbosity = 2, verbosityShift = 29, verbosityMask = 0x7 };
+
+ Stream(QIODevice *device) : ts(device), ref(1), type(QtDebugMsg),
+ space(true), message_output(false), flags(defaultVerbosity << verbosityShift) {}
+ Stream(QString *string) : ts(string, QIODevice::WriteOnly), ref(1), type(QtDebugMsg),
+ space(true), message_output(false), flags(defaultVerbosity << verbosityShift) {}
+ Stream(QtMsgType t) : ts(&buffer, QIODevice::WriteOnly), ref(1), type(t),
+ space(true), message_output(true), flags(defaultVerbosity << verbosityShift) {}
QTextStream ts;
QString buffer;
int ref;
@@ -64,7 +69,7 @@ class Q_CORE_EXPORT QDebug
bool message_output;
QMessageLogContext context;
- enum FormatFlag {
+ enum FormatFlag { // Note: Bits 29..31 are reserved for the verbose level introduced in 5.6.
NoQuotes = 0x1
};
@@ -72,7 +77,15 @@ class Q_CORE_EXPORT QDebug
bool testFlag(FormatFlag flag) const { return (context.version > 1) ? (flags & flag) : false; }
void setFlag(FormatFlag flag) { if (context.version > 1) { flags |= flag; } }
void unsetFlag(FormatFlag flag) { if (context.version > 1) { flags &= ~flag; } }
-
+ int verbosity() const
+ { return context.version > 1 ? (flags >> verbosityShift) & verbosityMask : int(Stream::defaultVerbosity); }
+ void setVerbosity(int v)
+ {
+ if (context.version > 1) {
+ flags &= ~(verbosityMask << verbosityShift);
+ flags |= (v & verbosityMask) << verbosityShift;
+ }
+ }
// added in 5.4
int flags;
} *stream;
@@ -96,6 +109,8 @@ public:
inline QDebug &space() { stream->space = true; stream->ts << ' '; return *this; }
inline QDebug &nospace() { stream->space = false; return *this; }
inline QDebug &maybeSpace() { if (stream->space) stream->ts << ' '; return *this; }
+ int verbosity() const { return stream->verbosity(); }
+ void setVerbosity(int verbosityLevel) { stream->setVerbosity(verbosityLevel); }
bool autoInsertSpaces() const { return stream->space; }
void setAutoInsertSpaces(bool b) { stream->space = b; }
diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp
index 3ee0e33573..4c5ed0aef6 100644
--- a/src/corelib/io/qfiledevice.cpp
+++ b/src/corelib/io/qfiledevice.cpp
@@ -481,7 +481,7 @@ bool QFileDevicePrivate::putCharHelper(char c)
#else
// Cutoff for code that doesn't only touch the buffer.
- int writeBufferSize = writeBuffer.size();
+ qint64 writeBufferSize = writeBuffer.size();
if ((openMode & QIODevice::Unbuffered) || writeBufferSize + 1 >= QFILE_WRITEBUFFER_SIZE
#ifdef Q_OS_WIN
|| ((openMode & QIODevice::Text) && c == '\n' && writeBufferSize + 2 >= QFILE_WRITEBUFFER_SIZE)
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index 6451bae0ba..d5c861f9ad 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -1912,12 +1912,12 @@ qint64 QProcess::readData(char *data, qint64 maxlen)
return 1;
}
- qint64 bytesToRead = qint64(qMin(readBuffer->size(), (int)maxlen));
+ qint64 bytesToRead = qMin(readBuffer->size(), maxlen);
qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
const char *ptr = readBuffer->readPointer();
- int bytesToReadFromThisBlock = qMin<qint64>(bytesToRead - readSoFar,
- readBuffer->nextDataBlockSize());
+ qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ readBuffer->nextDataBlockSize());
memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
readBuffer->free(bytesToReadFromThisBlock);
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp
index ab2025ee5c..1502e5dada 100644
--- a/src/corelib/io/qwindowspipereader.cpp
+++ b/src/corelib/io/qwindowspipereader.cpp
@@ -45,8 +45,8 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent)
handle(INVALID_HANDLE_VALUE),
readBufferMaxSize(0),
actualReadBufferSize(0),
- readSequenceStarted(false),
emitReadyReadTimer(new QTimer(this)),
+ readSequenceStarted(false),
pipeBroken(false),
readyReadEmitted(false)
{
@@ -133,12 +133,12 @@ qint64 QWindowsPipeReader::read(char *data, qint64 maxlen)
actualReadBufferSize--;
readSoFar = 1;
} else {
- qint64 bytesToRead = qMin(qint64(actualReadBufferSize), maxlen);
+ qint64 bytesToRead = qMin(actualReadBufferSize, maxlen);
readSoFar = 0;
while (readSoFar < bytesToRead) {
const char *ptr = readBuffer.readPointer();
- int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
- qint64(readBuffer.nextDataBlockSize()));
+ qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ readBuffer.nextDataBlockSize());
memcpy(data + readSoFar, ptr, bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
readBuffer.free(bytesToReadFromThisBlock);
diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h
index 7904f116cb..53872e2552 100644
--- a/src/corelib/io/qwindowspipereader_p.h
+++ b/src/corelib/io/qwindowspipereader_p.h
@@ -98,9 +98,9 @@ private:
QWinOverlappedIoNotifier *dataReadNotifier;
qint64 readBufferMaxSize;
QRingBuffer readBuffer;
- int actualReadBufferSize;
- bool readSequenceStarted;
+ qint64 actualReadBufferSize;
QTimer *emitReadyReadTimer;
+ bool readSequenceStarted;
bool pipeBroken;
bool readyReadEmitted;
};
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index b2b22ad99c..0a68de8871 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -150,7 +150,7 @@ QT_BEGIN_NAMESPACE
\value HoverLeave The mouse cursor leaves a hover widget (QHoverEvent).
\value HoverMove The mouse cursor moves inside a hover widget (QHoverEvent).
\value IconDrag The main icon of a window has been dragged away (QIconDragEvent).
- \value IconTextChange Widget's icon text has been changed.
+ \value IconTextChange Widget's icon text has been changed. (Deprecated)
\value InputMethod An input method is being used (QInputMethodEvent).
\value InputMethodQuery A input method query event (QInputMethodQueryEvent)
\value KeyboardLayoutChange The keyboard layout has changed.
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index c208eb1180..53da4a849b 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -133,7 +133,7 @@ public:
EnabledChange = 98, // enabled state has changed
ActivationChange = 99, // window activation has changed
StyleChange = 100, // style has changed
- IconTextChange = 101, // icon text has changed
+ IconTextChange = 101, // icon text has changed. Deprecated.
ModifiedChange = 102, // modified state has changed
MouseTrackingChange = 109, // mouse tracking state has changed
diff --git a/src/corelib/kernel/qjni.cpp b/src/corelib/kernel/qjni.cpp
index 694463b9d8..2290a74c31 100644
--- a/src/corelib/kernel/qjni.cpp
+++ b/src/corelib/kernel/qjni.cpp
@@ -204,6 +204,15 @@ static jfieldID getCachedFieldID(JNIEnv *env,
}
}
+void QJNILocalRefDeleter::cleanup(jobject obj)
+{
+ if (obj == 0)
+ return;
+
+ QJNIEnvironmentPrivate env;
+ env->DeleteLocalRef(obj);
+}
+
class QJNIEnvironmentPrivateTLS
{
public:
@@ -2258,4 +2267,3 @@ bool QJNIObjectPrivate::isSameObject(const QJNIObjectPrivate &other) const
}
QT_END_NAMESPACE
-
diff --git a/src/corelib/kernel/qjni_p.h b/src/corelib/kernel/qjni_p.h
index e79caed5b8..ae9c7c3a7e 100644
--- a/src/corelib/kernel/qjni_p.h
+++ b/src/corelib/kernel/qjni_p.h
@@ -51,6 +51,14 @@
QT_BEGIN_NAMESPACE
+struct Q_CORE_EXPORT QJNILocalRefDeleter
+{
+ static void cleanup(jobject obj);
+};
+
+// To simplify this we only define it for jobjects.
+typedef QScopedPointer<_jobject, QJNILocalRefDeleter> QJNIScopedLocalRef;
+
class Q_CORE_EXPORT QJNIEnvironmentPrivate
{
public:
diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp
index dad2d5dc1e..f77fc4220c 100644
--- a/src/corelib/kernel/qjnihelpers.cpp
+++ b/src/corelib/kernel/qjnihelpers.cpp
@@ -122,6 +122,45 @@ void QtAndroidPrivate::handleNewIntent(JNIEnv *env, jobject intent)
}
}
+namespace {
+ class ResumePauseListeners
+ {
+ public:
+ QMutex mutex;
+ QList<QtAndroidPrivate::ResumePauseListener *> listeners;
+ };
+}
+
+Q_GLOBAL_STATIC(ResumePauseListeners, g_resumePauseListeners)
+
+void QtAndroidPrivate::registerResumePauseListener(ResumePauseListener *listener)
+{
+ QMutexLocker locker(&g_resumePauseListeners()->mutex);
+ g_resumePauseListeners()->listeners.append(listener);
+}
+
+void QtAndroidPrivate::unregisterResumePauseListener(ResumePauseListener *listener)
+{
+ QMutexLocker locker(&g_resumePauseListeners()->mutex);
+ g_resumePauseListeners()->listeners.removeAll(listener);
+}
+
+void QtAndroidPrivate::handlePause()
+{
+ QMutexLocker locker(&g_resumePauseListeners()->mutex);
+ const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
+ for (int i=0; i<listeners.size(); ++i)
+ listeners.at(i)->handlePause();
+}
+
+void QtAndroidPrivate::handleResume()
+{
+ QMutexLocker locker(&g_resumePauseListeners()->mutex);
+ const QList<QtAndroidPrivate::ResumePauseListener *> &listeners = g_resumePauseListeners()->listeners;
+ for (int i=0; i<listeners.size(); ++i)
+ listeners.at(i)->handleResume();
+}
+
static inline bool exceptionCheck(JNIEnv *env)
{
if (env->ExceptionCheck()) {
diff --git a/src/corelib/kernel/qjnihelpers_p.h b/src/corelib/kernel/qjnihelpers_p.h
index 3ed8338b18..883b08ef60 100644
--- a/src/corelib/kernel/qjnihelpers_p.h
+++ b/src/corelib/kernel/qjnihelpers_p.h
@@ -68,6 +68,14 @@ namespace QtAndroidPrivate
virtual bool handleNewIntent(JNIEnv *env, jobject intent) = 0;
};
+ class Q_CORE_EXPORT ResumePauseListener
+ {
+ public:
+ virtual ~ResumePauseListener() {}
+ virtual void handlePause() {};
+ virtual void handleResume() {};
+ };
+
Q_CORE_EXPORT jobject activity();
Q_CORE_EXPORT JavaVM *javaVM();
Q_CORE_EXPORT jint initJNI(JavaVM *vm, JNIEnv *env);
@@ -82,6 +90,11 @@ namespace QtAndroidPrivate
Q_CORE_EXPORT void handleNewIntent(JNIEnv *env, jobject intent);
Q_CORE_EXPORT void registerNewIntentListener(NewIntentListener *listener);
Q_CORE_EXPORT void unregisterNewIntentListener(NewIntentListener *listener);
+
+ Q_CORE_EXPORT void handlePause();
+ Q_CORE_EXPORT void handleResume();
+ Q_CORE_EXPORT void registerResumePauseListener(ResumePauseListener *listener);
+ Q_CORE_EXPORT void unregisterResumePauseListener(ResumePauseListener *listener);
}
QT_END_NAMESPACE
diff --git a/src/corelib/plugin/qpluginloader.cpp b/src/corelib/plugin/qpluginloader.cpp
index 8ed9199c60..2800656c13 100644
--- a/src/corelib/plugin/qpluginloader.cpp
+++ b/src/corelib/plugin/qpluginloader.cpp
@@ -273,6 +273,13 @@ bool QPluginLoader::isLoaded() const
#if defined(QT_SHARED)
static QString locatePlugin(const QString& fileName)
{
+ const bool isAbsolute = QDir::isAbsolutePath(fileName);
+ if (isAbsolute) {
+ QFileInfo fi(fileName);
+ if (fi.isFile()) {
+ return fi.canonicalFilePath();
+ }
+ }
QStringList prefixes = QLibraryPrivate::prefixes_sys();
prefixes.prepend(QString());
QStringList suffixes = QLibraryPrivate::suffixes_sys(QString());
@@ -281,12 +288,18 @@ static QString locatePlugin(const QString& fileName)
// Split up "subdir/filename"
const int slash = fileName.lastIndexOf('/');
const QString baseName = fileName.mid(slash + 1);
- const QString basePath = fileName.left(slash + 1); // keep the '/'
+ const QString basePath = isAbsolute ? QString() : fileName.left(slash + 1); // keep the '/'
const bool debug = qt_debug_component();
- QStringList paths = QCoreApplication::libraryPaths();
- paths.prepend(QStringLiteral("./")); // search in current dir first
+ QStringList paths;
+ if (isAbsolute) {
+ paths.append(fileName.left(slash)); // don't include the '/'
+ } else {
+ paths = QCoreApplication::libraryPaths();
+ paths.prepend(QStringLiteral(".")); // search in current dir first
+ }
+
foreach (const QString &path, paths) {
foreach (const QString &prefix, prefixes) {
foreach (const QString &suffix, suffixes) {
@@ -337,12 +350,7 @@ void QPluginLoader::setFileName(const QString &fileName)
did_load = false;
}
- QFileInfo fi(fileName);
- QString fn;
- if (fi.isAbsolute())
- fn = fi.canonicalFilePath();
- else
- fn = locatePlugin(fileName);
+ const QString fn = locatePlugin(fileName);
d = QLibraryPrivate::findOrCreate(fn, QString(), lh);
if (!fn.isEmpty())
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 760ac59bf4..a681688d46 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -1430,9 +1430,11 @@ void QStateMachinePrivate::_q_process()
Q_ASSERT(!processing);
processing = true;
processingScheduled = false;
+ beginMacrostep();
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": starting the event processing loop";
#endif
+ bool didChange = false;
while (processing) {
if (stop) {
processing = false;
@@ -1473,15 +1475,17 @@ void QStateMachinePrivate::_q_process()
}
}
if (!enabledTransitions.isEmpty()) {
+ didChange = true;
q->beginMicrostep(e);
microstep(e, enabledTransitions.toList());
q->endMicrostep(e);
}
-#ifdef QSTATEMACHINE_DEBUG
else {
+ noMicrostep();
+#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": no transitions enabled";
- }
#endif
+ }
delete e;
}
#ifdef QSTATEMACHINE_DEBUG
@@ -1494,6 +1498,7 @@ void QStateMachinePrivate::_q_process()
switch (stopProcessingReason) {
case EventQueueEmpty:
+ processedPendingEvents(didChange);
break;
case Finished:
state = NotRunning;
@@ -1510,6 +1515,7 @@ void QStateMachinePrivate::_q_process()
emit q->runningChanged(false);
break;
}
+ endMacrostep(didChange);
}
void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
@@ -1619,6 +1625,47 @@ void QStateMachinePrivate::cancelAllDelayedEvents()
delayedEvents.clear();
}
+/*
+ This function is called when the state machine is performing no
+ microstep because no transition is enabled (i.e. an event is ignored).
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::noMicrostep()
+{ }
+
+/*
+ This function is called when the state machine has reached a stable
+ state (no pending events), and has not finished yet.
+ For each event the state machine receives it is guaranteed that
+ 1) beginMacrostep is called
+ 2) selectTransition is called at least once
+ 3) begin/endMicrostep is called at least once or noMicrostep is called
+ at least once (possibly both, but at least one)
+ 4) the state machine either enters an infinite loop, or stops (runningChanged(false),
+ and either finished or stopped are emitted), or processedPendingEvents() is called.
+ 5) if the machine is not in an infinite loop endMacrostep is called
+
+ didChange is set to true if at least one microstep was performed, it is possible
+ that the machine returned to exactly the same state as before, but some transitions
+ were triggered.
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::processedPendingEvents(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
+void QStateMachinePrivate::beginMacrostep()
+{ }
+
+void QStateMachinePrivate::endMacrostep(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
+
namespace _QStateMachine_Internal{
class GoToStateTransition : public QAbstractTransition
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index 3a93c47c5b..b7f2644255 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -123,6 +123,10 @@ public:
QAbstractTransition *createInitialTransition() const;
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
+ virtual void noMicrostep();
+ virtual void processedPendingEvents(bool didChange);
+ virtual void beginMacrostep();
+ virtual void endMacrostep(bool didChange);
bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
diff --git a/src/corelib/tools/qcommandlineoption.cpp b/src/corelib/tools/qcommandlineoption.cpp
index 7f898f68a8..51723f4a57 100644
--- a/src/corelib/tools/qcommandlineoption.cpp
+++ b/src/corelib/tools/qcommandlineoption.cpp
@@ -42,6 +42,7 @@ class QCommandLineOptionPrivate : public QSharedData
{
public:
inline QCommandLineOptionPrivate()
+ : hidden(false)
{ }
void setNames(const QStringList &nameList);
@@ -58,6 +59,9 @@ public:
//! The list of default values used for this option.
QStringList defaultValues;
+
+ //! Show or hide in --help
+ bool hidden;
};
/*!
@@ -362,4 +366,30 @@ QStringList QCommandLineOption::defaultValues() const
return d->defaultValues;
}
+/*!
+ Sets whether to hide this option in the user-visible help output.
+
+ All options are visible by default. Setting \a hidden to true for
+ a particular option makes it internal, i.e. not listed in the help output.
+
+ \since 5.6
+ \sa isHidden
+ */
+void QCommandLineOption::setHidden(bool hide)
+{
+ d->hidden = hide;
+}
+
+/*!
+ Returns true if this option is omitted from the help output,
+ false if the option is listed.
+
+ \since 5.6
+ \sa setHidden()
+ */
+bool QCommandLineOption::isHidden() const
+{
+ return d->hidden;
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qcommandlineoption.h b/src/corelib/tools/qcommandlineoption.h
index cf4160ecd2..85fc5ca6dd 100644
--- a/src/corelib/tools/qcommandlineoption.h
+++ b/src/corelib/tools/qcommandlineoption.h
@@ -77,6 +77,9 @@ public:
void setDefaultValues(const QStringList &defaultValues);
QStringList defaultValues() const;
+ void setHidden(bool hidden);
+ bool isHidden() const;
+
private:
QSharedDataPointer<QCommandLineOptionPrivate> d;
};
diff --git a/src/corelib/tools/qcommandlineparser.cpp b/src/corelib/tools/qcommandlineparser.cpp
index 21bc14a272..7e49253f9b 100644
--- a/src/corelib/tools/qcommandlineparser.cpp
+++ b/src/corelib/tools/qcommandlineparser.cpp
@@ -53,6 +53,7 @@ class QCommandLineParserPrivate
public:
inline QCommandLineParserPrivate()
: singleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions),
+ optionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsOptions),
builtinVersionOption(false),
builtinHelpOption(false),
needsParsing(true)
@@ -103,6 +104,9 @@ public:
//! The parsing mode for "-abc"
QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode;
+ //! How to parse "arg -option"
+ QCommandLineParser::OptionsAfterPositionalArgumentsMode optionsAfterPositionalArgumentsMode;
+
//! Whether addVersionOption was called
bool builtinVersionOption;
@@ -299,6 +303,41 @@ void QCommandLineParser::setSingleDashWordOptionMode(QCommandLineParser::SingleD
}
/*!
+ \enum QCommandLineParser::OptionsAfterPositionalArgumentsMode
+
+ This enum describes the way the parser interprets options that
+ occur after positional arguments.
+
+ \value ParseAsOptions \c{application argument --opt -t} is interpreted as setting
+ the options \c{opt} and \c{t}, just like \c{application --opt -t argument} would do.
+ This is the default parsing mode. In order to specify that \c{--opt} and \c{-t}
+ are positional arguments instead, the user can use \c{--}, as in
+ \c{application argument -- --opt -t}.
+
+ \value ParseAsPositionalArguments \c{application argument --opt} is interpreted as
+ having two positional arguments, \c{argument} and \c{--opt}.
+ This mode is useful for executables that aim to launch other executables
+ (e.g. wrappers, debugging tools, etc.) or that support internal commands
+ followed by options for the command. \c{argument} is the name of the command,
+ and all options occurring after it can be collected and parsed by another
+ command line parser, possibly in another executable.
+
+ \sa setOptionsAfterPositionalArgumentsMode()
+
+ \since 5.5
+*/
+
+/*!
+ Sets the parsing mode to \a parsingMode.
+ This must be called before process() or parse().
+ \since 5.5
+*/
+void QCommandLineParser::setOptionsAfterPositionalArgumentsMode(QCommandLineParser::OptionsAfterPositionalArgumentsMode parsingMode)
+{
+ d->optionsAfterPositionalArgumentsMode = parsingMode;
+}
+
+/*!
Adds the option \a option to look for while parsing.
Returns \c true if adding the option was successful; otherwise returns \c false.
@@ -640,7 +679,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
const QLatin1Char dashChar('-');
const QLatin1Char assignChar('=');
- bool doubleDashFound = false;
+ bool forcePositional = false;
errorText.clear();
positionalArgumentList.clear();
optionNames.clear();
@@ -658,7 +697,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
for (; argumentIterator != args.end() ; ++argumentIterator) {
QString argument = *argumentIterator;
- if (doubleDashFound) {
+ if (forcePositional) {
positionalArgumentList.append(argument);
} else if (argument.startsWith(doubleDashString)) {
if (argument.length() > 2) {
@@ -670,7 +709,7 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
error = true;
}
} else {
- doubleDashFound = true;
+ forcePositional = true;
}
} else if (argument.startsWith(dashChar)) {
if (argument.size() == 1) { // single dash ("stdin")
@@ -722,6 +761,8 @@ bool QCommandLineParserPrivate::parse(const QStringList &args)
}
} else {
positionalArgumentList.append(argument);
+ if (optionsAfterPositionalArgumentsMode == QCommandLineParser::ParseAsPositionalArguments)
+ forcePositional = true;
}
if (argumentIterator == args.end())
break;
@@ -1062,6 +1103,8 @@ QString QCommandLineParserPrivate::helpText() const
++longestOptionNameString;
for (int i = 0; i < commandLineOptionList.count(); ++i) {
const QCommandLineOption &option = commandLineOptionList.at(i);
+ if (option.isHidden())
+ continue;
text += wrapText(optionNameList.at(i), longestOptionNameString, option.description());
}
if (!positionalArgumentDefinitions.isEmpty()) {
diff --git a/src/corelib/tools/qcommandlineparser.h b/src/corelib/tools/qcommandlineparser.h
index 91a799b4d5..8c528ba69e 100644
--- a/src/corelib/tools/qcommandlineparser.h
+++ b/src/corelib/tools/qcommandlineparser.h
@@ -57,6 +57,12 @@ public:
};
void setSingleDashWordOptionMode(SingleDashWordOptionMode parsingMode);
+ enum OptionsAfterPositionalArgumentsMode {
+ ParseAsOptions,
+ ParseAsPositionalArguments
+ };
+ void setOptionsAfterPositionalArgumentsMode(OptionsAfterPositionalArgumentsMode mode);
+
bool addOption(const QCommandLineOption &commandLineOption);
bool addOptions(const QList<QCommandLineOption> &options);
diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h
index ead85e9da0..6f4ebcf420 100644
--- a/src/corelib/tools/qringbuffer_p.h
+++ b/src/corelib/tools/qringbuffer_p.h
@@ -58,7 +58,7 @@ public:
buffers.append(QByteArray());
}
- inline int nextDataBlockSize() const {
+ inline qint64 nextDataBlockSize() const {
return (tailBuffer == 0 ? tail : buffers.first().size()) - head;
}
@@ -86,9 +86,9 @@ public:
return 0;
}
- inline void free(int bytes) {
+ inline void free(qint64 bytes) {
while (bytes > 0) {
- int blockSize = buffers.first().size() - head;
+ const qint64 blockSize = buffers.first().size() - head;
if (tailBuffer == 0 || blockSize > bytes) {
// keep a single block around if it does not exceed
@@ -102,7 +102,8 @@ public:
clear(); // try to minify/squeeze us
}
} else {
- head += bytes;
+ Q_ASSERT(quint64(bytes) < QByteArray::MaxSize);
+ head += int(bytes);
bufferSize -= bytes;
}
return;
@@ -116,13 +117,15 @@ public:
}
}
- inline char *reserve(int bytes) {
- if (bytes <= 0)
+ inline char *reserve(qint64 bytes) {
+ if (bytes <= 0 || quint64(bytes) >= QByteArray::MaxSize)
return 0;
+ const qint64 newSize = bytes + tail;
// if need buffer reallocation
- if (tail + bytes > buffers.last().size()) {
- if (tail + bytes > buffers.last().capacity() && tail >= basicBlockSize) {
+ if (newSize > buffers.last().size()) {
+ if (newSize > buffers.last().capacity() && (tail >= basicBlockSize
+ || quint64(newSize) >= QByteArray::MaxSize)) {
// shrink this buffer to its current size
buffers.last().resize(tail);
@@ -131,21 +134,22 @@ public:
++tailBuffer;
tail = 0;
}
- buffers.last().resize(qMax(basicBlockSize, tail + bytes));
+ buffers.last().resize(qMax(basicBlockSize, tail + int(bytes)));
}
char *writePtr = buffers.last().data() + tail;
bufferSize += bytes;
- tail += bytes;
+ Q_ASSERT(quint64(bytes) < QByteArray::MaxSize);
+ tail += int(bytes);
return writePtr;
}
- inline void truncate(int pos) {
+ inline void truncate(qint64 pos) {
if (pos < size())
chop(size() - pos);
}
- inline void chop(int bytes) {
+ inline void chop(qint64 bytes) {
while (bytes > 0) {
if (tailBuffer == 0 || tail > bytes) {
// keep a single block around if it does not exceed
@@ -159,7 +163,8 @@ public:
clear(); // try to minify/squeeze us
}
} else {
- tail -= bytes;
+ Q_ASSERT(quint64(bytes) < QByteArray::MaxSize);
+ tail -= int(bytes);
bufferSize -= bytes;
}
return;
@@ -206,7 +211,7 @@ public:
++bufferSize;
}
- inline int size() const {
+ inline qint64 size() const {
return bufferSize;
}
@@ -219,9 +224,9 @@ public:
bufferSize = 0;
}
- inline int indexOf(char c) const {
- int index = 0;
- int j = head;
+ inline qint64 indexOf(char c) const {
+ qint64 index = 0;
+ qint64 j = head;
for (int i = 0; i < buffers.size(); ++i) {
const char *ptr = buffers[i].constData() + j;
j = index + (i == tailBuffer ? tail : buffers[i].size()) - j;
@@ -236,9 +241,9 @@ public:
return -1;
}
- inline int indexOf(char c, int maxLength) const {
- int index = 0;
- int j = head;
+ inline qint64 indexOf(char c, qint64 maxLength) const {
+ qint64 index = 0;
+ qint64 j = head;
for (int i = 0; index < maxLength && i < buffers.size(); ++i) {
const char *ptr = buffers[i].constData() + j;
j = qMin(index + (i == tailBuffer ? tail : buffers[i].size()) - j, maxLength);
@@ -253,11 +258,12 @@ public:
return -1;
}
- inline int read(char *data, int maxLength) {
- int bytesToRead = qMin(size(), maxLength);
- int readSoFar = 0;
+ inline qint64 read(char *data, qint64 maxLength) {
+ const qint64 bytesToRead = qMin(size(), maxLength);
+ qint64 readSoFar = 0;
while (readSoFar < bytesToRead) {
- int bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar, nextDataBlockSize());
+ const qint64 bytesToReadFromThisBlock = qMin(bytesToRead - readSoFar,
+ nextDataBlockSize());
if (data)
memcpy(data + readSoFar, readPointer(), bytesToReadFromThisBlock);
readSoFar += bytesToReadFromThisBlock;
@@ -300,15 +306,15 @@ public:
bufferSize += tail;
}
- inline int skip(int length) {
+ inline qint64 skip(qint64 length) {
return read(0, length);
}
- inline int readLine(char *data, int maxLength) {
+ inline qint64 readLine(char *data, qint64 maxLength) {
if (!data || --maxLength <= 0)
return -1;
- int i = indexOf('\n', maxLength);
+ qint64 i = indexOf('\n', maxLength);
i = read(data, i >= 0 ? (i + 1) : maxLength);
// Terminate it.
@@ -325,7 +331,7 @@ private:
int head, tail;
int tailBuffer; // always buffers.size() - 1
const int basicBlockSize;
- int bufferSize;
+ qint64 bufferSize;
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index e74a8eebee..8998b22be8 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ -7600,86 +7600,155 @@ static int getEscape(const QChar *uc, int *pos, int len, int maxNumber = 999)
return -1;
}
+/*
+ Algorithm for multiArg:
+
+ 1. Parse the string as a sequence of verbatim text and placeholders (%L?\d{,3}).
+ The L is parsed and accepted for compatibility with non-multi-arg, but since
+ multiArg only accepts strings as replacements, the localization request can
+ be safely ignored.
+ 2. The result of step (1) is a list of (string-ref,int)-tuples. The string-ref
+ either points at text to be copied verbatim (in which case the int is -1),
+ or, initially, at the textual representation of the placeholder. In that case,
+ the int contains the numerical number as parsed from the placeholder.
+ 3. Next, collect all the non-negative ints found, sort them in ascending order and
+ remove duplicates.
+ 3a. If the result has more entires than multiArg() was given replacement strings,
+ we have found placeholders we can't satisfy with replacement strings. That is
+ fine (there could be another .arg() call coming after this one), so just
+ truncate the result to the number of actual multiArg() replacement strings.
+ 3b. If the result has less entries than multiArg() was given replacement strings,
+ the string is missing placeholders. This is an error that the user should be
+ warned about.
+ 4. The result of step (3) is a mapping from the index of any replacement string to
+ placeholder number. This is the wrong way around, but since placeholder
+ numbers could get as large as 999, while we typically don't have more than 9
+ replacement strings, we trade 4K of sparsely-used memory for doing a reverse lookup
+ each time we need to map a placeholder number to a replacement string index
+ (that's a linear search; but still *much* faster than using an associative container).
+ 5. Next, for each of the tuples found in step (1), do the following:
+ 5a. If the int is negative, do nothing.
+ 5b. Otherwise, if the int is found in the result of step (3) at index I, replace
+ the string-ref with a string-ref for the (complete) I'th replacement string.
+ 5c. Otherwise, do nothing.
+ 6. Concatenate all string refs into a single result string.
+*/
+
namespace {
-class ArgMapper {
- QVarLengthArray<int, 16> argPosToNumberMap; // maps from argument position to number
-public:
- void found(int n) { argPosToNumberMap.push_back(n); }
+struct Part
+{
+ Part() : stringRef(), number(0) {}
+ Part(const QString &s, int pos, int len, int num = -1) Q_DECL_NOTHROW
+ : stringRef(&s, pos, len), number(num) {}
- struct AssignmentResult {
- int numArgs;
- int lastNumber;
- };
+ QStringRef stringRef;
+ int number;
+};
+} // unnamed namespace
- AssignmentResult assignArgumentNumberToEachOfTheNs(int numArgs)
- {
- std::sort(argPosToNumberMap.begin(), argPosToNumberMap.end());
- argPosToNumberMap.erase(std::unique(argPosToNumberMap.begin(), argPosToNumberMap.end()),
- argPosToNumberMap.end());
+template <>
+class QTypeInfo<Part> : public QTypeInfoMerger<Part, QStringRef, int> {}; // Q_DECLARE_METATYPE
- if (argPosToNumberMap.size() > numArgs)
- argPosToNumberMap.resize(numArgs);
- int lastNumber = argPosToNumberMap.empty() ? -1 : argPosToNumberMap.back();
- int arg = argPosToNumberMap.size();
+namespace {
- const AssignmentResult result = {arg, lastNumber};
- return result;
- }
+enum { ExpectedParts = 32 };
- int numberToArgsIndex(int number) const
- {
- if (number != -1) {
- const int * const it = std::find(argPosToNumberMap.begin(), argPosToNumberMap.end(), number);
- return it == argPosToNumberMap.end() ? -1 : it - argPosToNumberMap.begin();
- } else {
- return -1;
- }
- }
-};
-} // unnamed namespace
+typedef QVarLengthArray<Part, ExpectedParts> ParseResult;
+typedef QVarLengthArray<int, ExpectedParts/2> ArgIndexToPlaceholderMap;
-QString QString::multiArg(int numArgs, const QString **args) const
+static ParseResult parseMultiArgFormatString(const QString &s)
{
- QString result;
- ArgMapper mapper;
- const QChar *uc = (const QChar *) d->data();
- const int len = d->size;
+ ParseResult result;
+
+ const QChar *uc = s.constData();
+ const int len = s.size();
const int end = len - 1;
int i = 0;
+ int last = 0;
- // populate the arg-mapper with the %n's that actually occur in the string
while (i < end) {
if (uc[i] == QLatin1Char('%')) {
+ int percent = i;
int number = getEscape(uc, &i, len);
if (number != -1) {
- mapper.found(number);
+ if (last != percent)
+ result.push_back(Part(s, last, percent - last)); // literal text (incl. failed placeholders)
+ result.push_back(Part(s, percent, i - percent, number)); // parsed placeholder
+ last = i;
continue;
}
}
++i;
}
- const ArgMapper::AssignmentResult r = mapper.assignArgumentNumberToEachOfTheNs(numArgs);
+ if (last < len)
+ result.push_back(Part(s, last, len - last)); // trailing literal text
+
+ return result;
+}
- // sanity
- if (numArgs > r.numArgs) {
- qWarning("QString::arg: %d argument(s) missing in %s", numArgs - r.numArgs, toLocal8Bit().data());
- numArgs = r.numArgs;
+static ArgIndexToPlaceholderMap makeArgIndexToPlaceholderMap(const ParseResult &parts)
+{
+ ArgIndexToPlaceholderMap result;
+
+ for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) {
+ if (it->number >= 0)
+ result.push_back(it->number);
}
- i = 0;
- while (i < len) {
- if (uc[i] == QLatin1Char('%') && i != end) {
- int number = getEscape(uc, &i, len, r.lastNumber);
- int arg = mapper.numberToArgsIndex(number);
- if (number != -1 && arg != -1) {
- result += *args[arg];
- continue;
- }
+ std::sort(result.begin(), result.end());
+ result.erase(std::unique(result.begin(), result.end()),
+ result.end());
+
+ return result;
+}
+
+static int resolveStringRefsAndReturnTotalSize(ParseResult &parts, const ArgIndexToPlaceholderMap &argIndexToPlaceholderMap, const QString *args[])
+{
+ int totalSize = 0;
+ for (ParseResult::iterator pit = parts.begin(), end = parts.end(); pit != end; ++pit) {
+ if (pit->number != -1) {
+ const ArgIndexToPlaceholderMap::const_iterator ait
+ = std::find(argIndexToPlaceholderMap.begin(), argIndexToPlaceholderMap.end(), pit->number);
+ if (ait != argIndexToPlaceholderMap.end())
+ pit->stringRef = QStringRef(args[ait - argIndexToPlaceholderMap.begin()]);
}
- result += uc[i++];
+ totalSize += pit->stringRef.size();
}
+ return totalSize;
+}
+
+} // unnamed namespace
+
+QString QString::multiArg(int numArgs, const QString **args) const
+{
+ // Step 1-2 above
+ ParseResult parts = parseMultiArgFormatString(*this);
+
+ // 3-4
+ ArgIndexToPlaceholderMap argIndexToPlaceholderMap = makeArgIndexToPlaceholderMap(parts);
+
+ if (argIndexToPlaceholderMap.size() > numArgs) // 3a
+ argIndexToPlaceholderMap.resize(numArgs);
+ else if (argIndexToPlaceholderMap.size() < numArgs) // 3b
+ qWarning("QString::arg: %d argument(s) missing in %s",
+ numArgs - argIndexToPlaceholderMap.size(), toLocal8Bit().data());
+
+ // 5
+ const int totalSize = resolveStringRefsAndReturnTotalSize(parts, argIndexToPlaceholderMap, args);
+
+ // 6:
+ QString result(totalSize, Qt::Uninitialized);
+ QChar *out = result.data();
+
+ for (ParseResult::const_iterator it = parts.begin(), end = parts.end(); it != end; ++it) {
+ if (const int sz = it->stringRef.size()) {
+ memcpy(out, it->stringRef.constData(), sz * sizeof(QChar));
+ out += sz;
+ }
+ }
+
return result;
}
diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h
index 9d5b749e79..a48269cfaa 100644
--- a/src/corelib/tools/qvector.h
+++ b/src/corelib/tools/qvector.h
@@ -265,7 +265,6 @@ private:
{
return (i <= d->end()) && (d->begin() <= i);
}
- iterator c2m(const_iterator it) { return begin() + (it - cbegin()); }
class AlignmentDummy { Data header; T array[1]; };
};
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp
index 74d6a11dee..d7fa748a37 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1904,7 +1904,8 @@ int QDBusConnectionPrivate::send(const QDBusMessage& message)
qPrintable(message.interface()), qPrintable(message.member()),
qPrintable(error.message()));
else if (message.type() == QDBusMessage::SignalMessage)
- qWarning("QDBusConnection: error: could not send signal path \"%s\" interface \"%s\" member \"%s\": %s",
+ qWarning("QDBusConnection: error: could not send signal to service \"%s\" path \"%s\" interface \"%s\" member \"%s\": %s",
+ qPrintable(message.service()),
qPrintable(message.path()), qPrintable(message.interface()),
qPrintable(message.member()),
qPrintable(error.message()));
diff --git a/src/dbus/qdbusmessage.cpp b/src/dbus/qdbusmessage.cpp
index 491e1273e7..76e994bbcf 100644
--- a/src/dbus/qdbusmessage.cpp
+++ b/src/dbus/qdbusmessage.cpp
@@ -153,8 +153,10 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
}
break;
case QDBusMessage::SignalMessage:
- // nothing can be empty here
+ // only the service name can be empty here
if (!d_ptr->parametersValidated) {
+ if (!QDBusUtil::checkBusName(d_ptr->service, QDBusUtil::EmptyAllowed, error))
+ return 0;
if (!QDBusUtil::checkObjectPath(d_ptr->path, QDBusUtil::EmptyNotAllowed, error))
return 0;
if (!QDBusUtil::checkInterfaceName(d_ptr->interface, QDBusUtil::EmptyAllowed, error))
@@ -165,6 +167,7 @@ DBusMessage *QDBusMessagePrivate::toDBusMessage(const QDBusMessage &message, QDB
msg = q_dbus_message_new_signal(d_ptr->path.toUtf8(), d_ptr->interface.toUtf8(),
d_ptr->name.toUtf8());
+ q_dbus_message_set_destination(msg, data(d_ptr->service.toUtf8()));
break;
}
@@ -372,6 +375,31 @@ QDBusMessage QDBusMessage::createSignal(const QString &path, const QString &inte
}
/*!
+ \since 5.6
+
+ Constructs a new DBus message with the given \a path, \a interface
+ and \a name, representing a signal emission to \a destination.
+
+ A DBus signal is emitted from one application and is received only by
+ the application owning the destination service name.
+
+ The QDBusMessage object that is returned can be sent using the
+ QDBusConnection::send() function.
+*/
+QDBusMessage QDBusMessage::createTargetedSignal(const QString &service, const QString &path,
+ const QString &interface, const QString &name)
+{
+ QDBusMessage message;
+ message.d_ptr->type = SignalMessage;
+ message.d_ptr->service = service;
+ message.d_ptr->path = path;
+ message.d_ptr->interface = interface;
+ message.d_ptr->name = name;
+
+ return message;
+}
+
+/*!
Constructs a new DBus message representing a method call.
A method call always informs its destination address
(\a service, \a path, \a interface and \a method).
diff --git a/src/dbus/qdbusmessage.h b/src/dbus/qdbusmessage.h
index 77f34ec5e2..640226e77a 100644
--- a/src/dbus/qdbusmessage.h
+++ b/src/dbus/qdbusmessage.h
@@ -67,6 +67,8 @@ public:
static QDBusMessage createSignal(const QString &path, const QString &interface,
const QString &name);
+ static QDBusMessage createTargetedSignal(const QString &service, const QString &path,
+ const QString &interface, const QString &name);
static QDBusMessage createMethodCall(const QString &destination, const QString &path,
const QString &interface, const QString &method);
static QDBusMessage createError(const QString &name, const QString &msg);
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 038be09dc7..5785722918 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -37,6 +37,7 @@
#include "qguiapplication_p.h"
#include <qpa/qplatformscreen.h>
+#include <QtCore/QDebug>
#include <QtCore/private/qobject_p.h>
QT_BEGIN_NAMESPACE
@@ -654,4 +655,41 @@ QPixmap QScreen::grabWindow(WId window, int x, int y, int width, int height)
return platformScreen->grabWindow(window, x, y, width, height);
}
+#ifndef QT_NO_DEBUG_STREAM
+
+static inline void formatRect(QDebug &debug, const QRect r)
+{
+ debug << r.width() << 'x' << r.height()
+ << forcesign << r.x() << r.y() << noforcesign;
+}
+
+Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QScreen *screen)
+{
+ const QDebugStateSaver saver(debug);
+ debug.nospace();
+ debug << "QScreen(" << (void *)screen;
+ if (screen) {
+ debug << ", name=" << screen->name();
+ if (debug.verbosity() > 2) {
+ if (screen == QGuiApplication::primaryScreen())
+ debug << ", primary";
+ debug << ", geometry=";
+ formatRect(debug, screen->geometry());
+ debug << ", available=";
+ formatRect(debug, screen->availableGeometry());
+ debug << ", logical DPI=" << screen->logicalDotsPerInchX()
+ << ',' << screen->logicalDotsPerInchY()
+ << ", physical DPI=" << screen->physicalDotsPerInchX()
+ << ',' << screen->physicalDotsPerInchY()
+ << ", devicePixelRatio=" << screen->devicePixelRatio()
+ << ", orientation=" << screen->orientation()
+ << ", physical size=" << screen->physicalSize().width()
+ << 'x' << screen->physicalSize().height() << "mm";
+ }
+ }
+ debug << ')';
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index 255e735baf..f60fafcf63 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -52,6 +52,9 @@ class QScreenPrivate;
class QWindow;
class QRect;
class QPixmap;
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
class Q_GUI_EXPORT QScreen : public QObject
{
@@ -153,6 +156,10 @@ private:
friend class QPlatformScreen;
};
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QScreen *);
+#endif
+
QT_END_NAMESPACE
#endif // QSCREEN_H
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 06674d204d..fd4c769049 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -2458,6 +2458,45 @@ void QWindowPrivate::applyCursor()
}
#endif // QT_NO_CURSOR
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug debug, const QWindow *window)
+{
+ QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (window) {
+ debug << window->metaObject()->className() << '(' << (void *)window;
+ if (!window->objectName().isEmpty())
+ debug << ", name=" << window->objectName();
+ if (debug.verbosity() > 2) {
+ const QRect geometry = window->geometry();
+ if (window->isVisible())
+ debug << ", visible";
+ if (window->isExposed())
+ debug << ", exposed";
+ debug << ", state=" << window->windowState()
+ << ", type=" << window->type() << ", flags=" << window->flags()
+ << ", surface type=" << window->surfaceType();
+ if (window->isTopLevel())
+ debug << ", toplevel";
+ debug << ", " << geometry.width() << 'x' << geometry.height()
+ << forcesign << geometry.x() << geometry.y() << noforcesign;
+ const QMargins margins = window->frameMargins();
+ if (!margins.isNull())
+ debug << ", margins=" << margins;
+ debug << ", devicePixelRatio=" << window->devicePixelRatio();
+ if (const QPlatformWindow *platformWindow = window->handle())
+ debug << ", winId=0x" << hex << platformWindow->winId() << dec;
+ if (const QScreen *screen = window->screen())
+ debug << ", on " << screen->name();
+ }
+ debug << ')';
+ } else {
+ debug << "QWindow(0x0)";
+ }
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#include "moc_qwindow.cpp"
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index f9fe37718c..67585ce963 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -78,6 +78,9 @@ class QBackingStore;
class QScreen;
class QAccessibleInterface;
class QWindowContainer;
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
class Q_GUI_EXPORT QWindow : public QObject, public QSurface
{
@@ -367,6 +370,10 @@ template <> inline const QWindow *qobject_cast<const QWindow*>(const QObject *o)
}
#endif // !Q_QDOC
+#ifndef QT_NO_DEBUG_STREAM
+Q_GUI_EXPORT QDebug operator<<(QDebug, const QWindow *);
+#endif
+
QT_END_NAMESPACE
#endif // QWINDOW_H
diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp
index 73b1a84005..7bf47a1dc8 100644
--- a/src/gui/kernel/qwindowsysteminterface.cpp
+++ b/src/gui/kernel/qwindowsysteminterface.cpp
@@ -427,6 +427,7 @@ void QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfa
{
if (synchronousWindowsSystemEvents) {
QGuiApplicationPrivate::processWindowSystemEvent(ev);
+ delete ev;
} else {
windowSystemEventQueue.append(ev);
QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::qt_qpa_core_dispatcher();
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 2f2d3daaf8..3010d4052a 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -43,6 +43,7 @@ HEADERS += \
painting/qrasterizer_p.h \
painting/qregion.h \
painting/qrgb.h \
+ painting/qrgba64.h \
painting/qstroker_p.h \
painting/qtextureglyphcache_p.h \
painting/qtransform.h \
diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp
index 945b150375..806c9362ac 100644
--- a/src/gui/painting/qcolor.cpp
+++ b/src/gui/painting/qcolor.cpp
@@ -416,6 +416,18 @@ QColor::QColor(QRgb color)
ct.argb.pad = 0;
}
+/*!
+ \since 5.6
+
+ Constructs a color with the value \a rgba64.
+
+ \sa fromRgba64()
+*/
+
+QColor::QColor(QRgba64 rgba64)
+{
+ setRgba64(rgba64);
+}
/*!
\internal
@@ -941,7 +953,7 @@ void QColor::setRgb(int r, int g, int b, int a)
For an invalid color, the alpha value of the returned color is unspecified.
- \sa setRgba(), rgb()
+ \sa setRgba(), rgb(), rgba64()
*/
QRgb QColor::rgba() const
@@ -954,7 +966,7 @@ QRgb QColor::rgba() const
/*!
Sets the RGB value to \a rgba, including its alpha.
- \sa rgba(), rgb()
+ \sa rgba(), rgb(), setRgba64()
*/
void QColor::setRgba(QRgb rgba)
{
@@ -967,6 +979,40 @@ void QColor::setRgba(QRgb rgba)
}
/*!
+ \since 5.6
+
+ Returns the RGB64 value of the color, including its alpha.
+
+ For an invalid color, the alpha value of the returned color is unspecified.
+
+ \sa setRgba64(), rgba(), rgb()
+*/
+
+QRgba64 QColor::rgba64() const
+{
+ if (cspec != Invalid && cspec != Rgb)
+ return toRgb().rgba64();
+ return qRgba64(ct.argb.red, ct.argb.green, ct.argb.blue, ct.argb.alpha);
+}
+
+/*!
+ \since 5.6
+
+ Sets the RGB64 value to \a rgba, including its alpha.
+
+ \sa \setRgba(), rgba64()
+*/
+void QColor::setRgba64(QRgba64 rgba)
+{
+ cspec = Rgb;
+ ct.argb.alpha = rgba.alpha();
+ ct.argb.red = rgba.red();
+ ct.argb.green = rgba.green();
+ ct.argb.blue = rgba.blue();
+ ct.argb.pad = 0;
+}
+
+/*!
\fn QRgb QColor::rgb() const
Returns the RGB value of the color. The alpha value is opaque.
@@ -1850,7 +1896,7 @@ QColor QColor::fromRgb(QRgb rgb)
Unlike the fromRgb() function, the alpha-channel specified by the given
QRgb value is included.
- \sa fromRgb(), isValid()
+ \sa fromRgb(), fromRgba64(), isValid()
*/
QColor QColor::fromRgba(QRgb rgba)
@@ -1865,7 +1911,7 @@ QColor QColor::fromRgba(QRgb rgba)
All the values must be in the range 0-255.
- \sa toRgb(), fromRgbF(), isValid()
+ \sa toRgb(), fromRgba64(), fromRgbF(), isValid()
*/
QColor QColor::fromRgb(int r, int g, int b, int a)
{
@@ -1894,7 +1940,7 @@ QColor QColor::fromRgb(int r, int g, int b, int a)
All the values must be in the range 0.0-1.0.
- \sa fromRgb(), toRgb(), isValid()
+ \sa fromRgb(), fromRgba64(), toRgb(), isValid()
*/
QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a)
{
@@ -1916,6 +1962,38 @@ QColor QColor::fromRgbF(qreal r, qreal g, qreal b, qreal a)
return color;
}
+
+/*!
+ \since 5.6
+
+ Static convenience function that returns a QColor constructed from the RGBA64
+ color values, \a r (red), \a g (green), \a b (blue), and \a a
+ (alpha-channel, i.e. transparency).
+
+ \sa fromRgb(), fromRgbF(), toRgb(), isValid()
+*/
+QColor QColor::fromRgba64(ushort r, ushort g, ushort b, ushort a)
+{
+ QColor color;
+ color.setRgba64(qRgba64(r, g, b, a));
+ return color;
+}
+
+/*!
+ \since 5.6
+
+ Static convenience function that returns a QColor constructed from the
+ given QRgba64 value \a rgba64.
+
+ \sa fromRgb(), fromRgbF(), toRgb(), isValid()
+*/
+QColor QColor::fromRgba64(QRgba64 rgba64)
+{
+ QColor color;
+ color.setRgba64(rgba64);
+ return color;
+}
+
/*!
Static convenience function that returns a QColor constructed from the HSV
color values, \a h (hue), \a s (saturation), \a v (value), and \a a
diff --git a/src/gui/painting/qcolor.h b/src/gui/painting/qcolor.h
index 06c218365b..9175875310 100644
--- a/src/gui/painting/qcolor.h
+++ b/src/gui/painting/qcolor.h
@@ -37,6 +37,7 @@
#include <QtGui/qrgb.h>
#include <QtCore/qnamespace.h>
#include <QtCore/qstringlist.h>
+#include <QtGui/qrgba64.h>
QT_BEGIN_NAMESPACE
@@ -63,6 +64,7 @@ public:
QColor(Qt::GlobalColor color);
QColor(int r, int g, int b, int a = 255);
QColor(QRgb rgb);
+ QColor(QRgba64 rgba64);
QColor(const QString& name);
QColor(const char *name);
QColor(const QColor &color); // ### Qt 6: remove, the trivial one is fine.
@@ -109,6 +111,9 @@ public:
QRgb rgba() const;
void setRgba(QRgb rgba);
+ QRgba64 rgba64() const;
+ void setRgba64(QRgba64 rgba);
+
QRgb rgb() const;
void setRgb(QRgb rgb);
@@ -173,6 +178,9 @@ public:
static QColor fromRgb(int r, int g, int b, int a = 255);
static QColor fromRgbF(qreal r, qreal g, qreal b, qreal a = 1.0);
+ static QColor fromRgba64(ushort r, ushort g, ushort b, ushort a = USHRT_MAX);
+ static QColor fromRgba64(QRgba64 rgba);
+
static QColor fromHsv(int h, int s, int v, int a = 255);
static QColor fromHsvF(qreal h, qreal s, qreal v, qreal a = 1.0);
diff --git a/src/gui/painting/qrgba64.h b/src/gui/painting/qrgba64.h
new file mode 100644
index 0000000000..2ea09e6bd6
--- /dev/null
+++ b/src/gui/painting/qrgba64.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QRGBA64_H
+#define QRGBA64_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qprocessordetection.h>
+
+QT_BEGIN_NAMESPACE
+
+class QRgba64 {
+ union {
+ struct {
+ quint16 red;
+ quint16 green;
+ quint16 blue;
+ quint16 alpha;
+ } c;
+ quint64 rgba;
+ };
+public:
+ // No constructors are allowed, since this needs to be usable in a union in no-c++11 mode.
+ // When c++11 is mandatory, we can add all but a copy constructor.
+ Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint16 red, quint16 green, quint16 blue, quint16 alpha)
+ {
+ QRgba64 rgba64
+#ifdef Q_COMPILER_UNIFORM_INIT
+ = {}
+#endif
+ ;
+
+ rgba64.c.red = red;
+ rgba64.c.green = green;
+ rgba64.c.blue = blue;
+ rgba64.c.alpha = alpha;
+ return rgba64;
+ }
+ Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba64(quint64 c)
+ {
+ QRgba64 rgba64
+#ifdef Q_COMPILER_UNIFORM_INIT
+ = {}
+#endif
+ ;
+ rgba64.rgba = c;
+ return rgba64;
+ }
+ Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+ {
+ QRgba64 rgb64 = fromRgba64(red, green, blue, alpha);
+ // Expand the range so that 0x00 maps to 0x0000 and 0xff maps to 0xffff.
+ rgb64.rgba |= rgb64.rgba << 8;
+ return rgb64;
+ }
+ Q_DECL_RELAXED_CONSTEXPR static QRgba64 fromArgb32(uint rgb)
+ {
+ return fromRgba(rgb >> 16, rgb >> 8, rgb, rgb >> 24);
+ }
+
+ Q_DECL_CONSTEXPR quint16 red() const { return c.red; }
+ Q_DECL_CONSTEXPR quint16 green() const { return c.green; }
+ Q_DECL_CONSTEXPR quint16 blue() const { return c.blue; }
+ Q_DECL_CONSTEXPR quint16 alpha() const { return c.alpha; }
+ void setRed(quint16 _red) { c.red = _red; }
+ void setGreen(quint16 _green) { c.green = _green; }
+ void setBlue(quint16 _blue) { c.blue = _blue; }
+ void setAlpha(quint16 _alpha) { c.alpha = _alpha; }
+
+ Q_DECL_CONSTEXPR quint8 red8() const { return div_257(c.red); }
+ Q_DECL_CONSTEXPR quint8 green8() const { return div_257(c.green); }
+ Q_DECL_CONSTEXPR quint8 blue8() const { return div_257(c.blue); }
+ Q_DECL_CONSTEXPR quint8 alpha8() const { return div_257(c.alpha); }
+ Q_DECL_CONSTEXPR uint toArgb32() const
+ {
+ return (alpha8() << 24) | (red8() << 16) | (green8() << 8) | blue8();
+ }
+ Q_DECL_CONSTEXPR ushort toRgb16() const
+ {
+ return (c.red & 0xf800) | ((c.green >> 10) << 5) | (c.blue >> 11);
+ }
+
+ Q_DECL_RELAXED_CONSTEXPR QRgba64 premultiplied() const
+ {
+ const quint32 a = c.alpha;
+ const quint16 r = div_65535(c.red * a);
+ const quint16 g = div_65535(c.green * a);
+ const quint16 b = div_65535(c.blue * a);
+ return fromRgba64(r, g, b, a);
+ }
+
+ Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied() const
+ {
+#if Q_PROCESSOR_WORDSIZE < 8
+ return unpremultiplied_32bit();
+#else
+ return unpremultiplied_64bit();
+#endif
+ }
+
+ Q_DECL_CONSTEXPR operator quint64() const
+ {
+ return rgba;
+ }
+
+private:
+ static Q_DECL_CONSTEXPR uint div_257_floor(uint x) { return (x - (x >> 8)) >> 8; }
+ static Q_DECL_CONSTEXPR uint div_257(uint x) { return div_257_floor(x + 128); }
+ static Q_DECL_CONSTEXPR uint div_65535(uint x) { return (x + (x>>16) + 0x8000U) >> 16; }
+ Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_32bit() const
+ {
+ if (c.alpha == 0xffff || c.alpha == 0)
+ return *this;
+ const quint16 r = (quint32(c.red) * 0xffff + c.alpha/2) / c.alpha;
+ const quint16 g = (quint32(c.green) * 0xffff + c.alpha/2) / c.alpha;
+ const quint16 b = (quint32(c.blue) * 0xffff + c.alpha/2) / c.alpha;
+ return fromRgba64(r, g, b, c.alpha);
+ }
+ Q_DECL_RELAXED_CONSTEXPR QRgba64 unpremultiplied_64bit() const
+ {
+ if (c.alpha == 0xffff || c.alpha == 0)
+ return *this;
+ const quint64 fa = (Q_UINT64_C(0xffff00008000) + c.alpha/2) / c.alpha;
+ const quint16 r = (c.red * fa + 0x80000000) >> 32;
+ const quint16 g = (c.green * fa + 0x80000000) >> 32;
+ const quint16 b = (c.blue * fa + 0x80000000) >> 32;
+ return fromRgba64(r, g, b, c.alpha);
+ }
+};
+
+Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+{
+ return QRgba64::fromRgba64(r, g, b, a);
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qRgba64(quint64 c)
+{
+ return QRgba64::fromRgba64(c);
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qPremultiply(QRgba64 c)
+{
+ return c.premultiplied();
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline QRgba64 qUnpremultiply(QRgba64 c)
+{
+ return c.unpremultiplied();
+}
+
+inline Q_DECL_CONSTEXPR uint qRed(QRgba64 rgb)
+{ return rgb.red8(); }
+
+inline Q_DECL_CONSTEXPR uint qGreen(QRgba64 rgb)
+{ return rgb.green8(); }
+
+inline Q_DECL_CONSTEXPR uint qBlue(QRgba64 rgb)
+{ return rgb.blue8(); }
+
+inline Q_DECL_CONSTEXPR uint qAlpha(QRgba64 rgb)
+{ return rgb.alpha8(); }
+
+QT_END_NAMESPACE
+
+#endif // QRGBA64_H
diff --git a/src/gui/painting/qrgba64.qdoc b/src/gui/painting/qrgba64.qdoc
new file mode 100644
index 0000000000..29da0aa390
--- /dev/null
+++ b/src/gui/painting/qrgba64.qdoc
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \class QRgba64
+ \brief The QRgba64 struct contains a 64-bit RGB color.
+ \since 5.6
+
+ \ingroup painting
+ \inmodule QtGui
+
+ QRgba64 is a 64-bit data-structure containing four 16-bit color channels: Red, green, blue and alpha.
+
+ QRgba64 can be used a replacement for QRgb when higher precision is needed. In particular a
+ premultiplied QRgba64 can operate on unpremultipled QRgb without loss of precision except
+ for alpha 0.
+
+ \sa QRgb, QColor
+*/
+
+/*!
+ \fn static QRgba64 QRgba64::fromRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+
+ Returns the QRgba64 quadruplet (\a{r}, \a{g}, \a{b}, \a{a}).
+
+ \sa fromRgba()
+*/
+
+/*!
+ \fn static QRgba64 QRgba64::fromRgba64(quint64 c)
+
+ Returns \a c as a QRgba64 struct.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn static QRgba64 QRgba64::fromRgba(quint8 red, quint8 green, quint8 blue, quint8 alpha)
+
+ Constructs a QRgba64 value from the four 8-bit color channels \a red, \a green, \a blue and \a alpha.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn static QRgba64 QRgba64::fromArgb32(uint rgb)
+
+ Constructs a QRgba64 value from the 32bit ARGB value \a rgb.
+
+ \sa fromRgba()
+*/
+
+/*!
+ \fn quint16 QRgba64::red() const
+
+ Returns the 16-bit red color component.
+*/
+
+/*!
+ \fn quint16 QRgba64::green() const
+
+ Returns the 16-bit green color component.
+*/
+
+/*!
+ \fn quint16 QRgba64::blue() const
+
+ Returns the 16-bit blue color component.
+*/
+
+/*!
+ \fn quint16 QRgba64::alpha() const
+
+ Returns the 16-bit alpha channel.
+*/
+
+/*!
+ \fn quint8 QRgba64::red8() const
+
+ Returns the red color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgba64::green8() const
+
+ Returns the green color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgba64::blue8() const
+
+ Returns the blue color component as an 8-bit.
+*/
+
+/*!
+ \fn quint8 QRgba64::alpha8() const
+
+ Returns the alpha channel as an 8-bit.
+*/
+
+/*!
+ \fn uint QRgba64::toArgb32() const
+
+ Returns the color as a 32-bit ARGB value.
+
+ \sa fromArgb32()
+*/
+
+/*!
+ \fn ushort QRgba64::toRgb16() const
+
+ Returns the color as a 16-bit RGB value.
+
+ \sa toArgb32()
+*/
+
+/*!
+ \fn QRgba64 QRgba64::premultiplied() const
+
+ Returns the color with the alpha premultiplied.
+
+ \sa unpremultiplied()
+*/
+
+/*!
+ \fn QRgba64 QRgba64::unpremultiplied() const
+
+ Returns the color with the alpha unpremultiplied.
+
+ \sa premultiplied()
+*/
+
+/*!
+ \fn QRgba64::operator quint64() const
+
+ Returns the color as a 64bit unsigned integer
+*/
+
+/*!
+ \fn QRgba64 qRgba64(quint16 r, quint16 g, quint16 b, quint16 a)
+ \relates QColor
+ \since 5.6
+
+ Returns the QRgba64 quadruplet (\a{r}, \a{g}, \a{b}, \a{a}).
+
+ \sa qRgba()
+*/
+
+/*!
+ \fn QRgba64 qRgba64(quint64 c)
+ \relates QColor
+ \since 5.6
+
+ Returns \a c as a QRgba64 struct.
+
+ \sa qRgba()
+*/
+
+/*!
+ \fn QRgba64 qPremultiply(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Converts an unpremultiplied QRgba64 quadruplet \a rgba64 into a premultiplied QRgba64 quadruplet.
+
+ \sa QRgba64::premultiplied(), qUnpremultiply()
+*/
+
+/*!
+ \fn QRgba64 qUnpremultiply(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Converts a premultiplied QRgba64 quadruplet \a rgba64 into an unpremultiplied QRgba64 quadruplet.
+
+ \sa QRgba64::unpremultiplied(), qPremultiply()
+*/
+
+/*!
+ \fn uint qRed(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Returns the red component of \a rgba64 as an 8-bit value.
+
+ \sa QRgba64::red8(), QColor::red()
+*/
+
+/*!
+ \fn uint qGreen(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Returns the green component of \a rgba64 as an 8-bit value.
+
+ \sa QRgba64::green8(), QColor::green()
+*/
+
+/*!
+ \fn uint qBlue(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Returns the blue component of \a rgba64 as an 8-bit value.
+
+ \sa QRgba64::blue8(), QColor::blue()
+*/
+
+/*!
+ \fn uint qAlpha(QRgba64 rgba64)
+ \since 5.6
+ \relates QColor
+
+ Returns the alpha component of \a rgba64 as an 8-bit value.
+
+ \sa QRgba64::alpha8(), QColor::alpha()
+*/
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 7a848dcfcd..0732a38a6e 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -506,6 +506,53 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
return false;
}
+QUrl QHttpNetworkConnectionPrivate::parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply)
+{
+ if (!reply->request().isFollowRedirects())
+ return QUrl();
+
+ QUrl rUrl;
+ QList<QPair<QByteArray, QByteArray> > fields = reply->header();
+ foreach (const QNetworkReply::RawHeaderPair &header, fields) {
+ if (header.first.toLower() == "location") {
+ rUrl = QUrl::fromEncoded(header.second);
+ break;
+ }
+ }
+
+ // If the location url is invalid/empty, we emit ProtocolUnknownError
+ if (!rUrl.isValid()) {
+ emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
+ return QUrl();
+ }
+
+ // Check if we have exceeded max redirects allowed
+ if (reply->request().redirectCount() <= 0) {
+ emitReplyError(socket, reply, QNetworkReply::TooManyRedirectsError);
+ return QUrl();
+ }
+
+ // Resolve the URL if it's relative
+ if (rUrl.isRelative())
+ rUrl = reply->request().url().resolved(rUrl);
+
+ // Check redirect url protocol
+ QString scheme = rUrl.scheme();
+ if (scheme == QLatin1String("http") || scheme == QLatin1String("https")) {
+ QString previousUrlScheme = reply->request().url().scheme();
+ // Check if we're doing an unsecure redirect (https -> http)
+ if (previousUrlScheme == QLatin1String("https")
+ && scheme == QLatin1String("http")) {
+ emitReplyError(socket, reply, QNetworkReply::InsecureRedirectError);
+ return QUrl();
+ }
+ } else {
+ emitReplyError(socket, reply, QNetworkReply::ProtocolUnknownError);
+ return QUrl();
+ }
+ return rUrl;
+}
+
void QHttpNetworkConnectionPrivate::createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request)
{
Q_ASSERT(socket);
@@ -802,6 +849,12 @@ QString QHttpNetworkConnectionPrivate::errorDetail(QNetworkReply::NetworkError e
case QNetworkReply::SslHandshakeFailedError:
errorString = QCoreApplication::translate("QHttp", "SSL handshake failed");
break;
+ case QNetworkReply::TooManyRedirectsError:
+ errorString = QCoreApplication::translate("QHttp", "Too many redirects");
+ break;
+ case QNetworkReply::InsecureRedirectError:
+ errorString = QCoreApplication::translate("QHttp", "Insecure redirect");
+ break;
default:
// all other errors are treated as QNetworkReply::UnknownNetworkError
errorString = extraDetail;
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index 115eef581e..9af39d416a 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -250,6 +250,7 @@ public:
void emitReplyError(QAbstractSocket *socket, QHttpNetworkReply *reply, QNetworkReply::NetworkError errorCode);
bool handleAuthenticateChallenge(QAbstractSocket *socket, QHttpNetworkReply *reply, bool isProxy, bool &resend);
+ QUrl parseRedirectResponse(QAbstractSocket *socket, QHttpNetworkReply *reply);
#ifndef QT_NO_NETWORKPROXY
QNetworkProxy networkProxy;
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index 75888c0062..647967839a 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -492,6 +492,20 @@ void QHttpNetworkConnectionChannel::handleStatus()
bool resend = false;
switch (statusCode) {
+ case 301:
+ case 302:
+ case 303:
+ case 305:
+ case 307: {
+ // Parse the response headers and get the "location" url
+ QUrl redirectUrl = connection->d_func()->parseRedirectResponse(socket, reply);
+ if (redirectUrl.isValid())
+ reply->setRedirectUrl(redirectUrl);
+
+ if (qobject_cast<QHttpNetworkConnection *>(connection))
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ break;
+ }
case 401: // auth required
case 407: // proxy auth required
if (connection->d_func()->handleAuthenticateChallenge(socket, reply, (statusCode == 407), resend)) {
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index 2063ca6bd0..172d4dab5b 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -78,6 +78,23 @@ void QHttpNetworkReply::setUrl(const QUrl &url)
d->url = url;
}
+QUrl QHttpNetworkReply::redirectUrl() const
+{
+ return d_func()->redirectUrl;
+}
+
+void QHttpNetworkReply::setRedirectUrl(const QUrl &url)
+{
+ Q_D(QHttpNetworkReply);
+ d->redirectUrl = url;
+}
+
+bool QHttpNetworkReply::isHttpRedirect(int statusCode)
+{
+ return (statusCode == 301 || statusCode == 302 || statusCode == 303
+ || statusCode == 305 || statusCode == 307);
+}
+
qint64 QHttpNetworkReply::contentLength() const
{
return d_func()->contentLength();
@@ -267,6 +284,11 @@ void QHttpNetworkReply::setSpdyWasUsed(bool spdy)
d_func()->spdyUsed = spdy;
}
+bool QHttpNetworkReply::isRedirecting() const
+{
+ return d_func()->isRedirecting();
+}
+
QHttpNetworkConnection* QHttpNetworkReply::connection()
{
return d_func()->connection;
@@ -910,6 +932,14 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QAbstractSocket *socket, qint64 *c
return bytes;
}
+bool QHttpNetworkReplyPrivate::isRedirecting() const
+{
+ // We're in the process of redirecting - if the HTTP status code says so and
+ // followRedirect is switched on
+ return (QHttpNetworkReply::isHttpRedirect(statusCode)
+ && request.isFollowRedirects());
+}
+
bool QHttpNetworkReplyPrivate::shouldEmitSignals()
{
// for 401 & 407 don't emit the data signals. Content along with these
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 0fe298da27..6e81663500 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -127,8 +127,15 @@ public:
bool isSpdyUsed() const;
void setSpdyWasUsed(bool spdy);
+ bool isRedirecting() const;
+
QHttpNetworkConnection* connection();
+ QUrl redirectUrl() const;
+ void setRedirectUrl(const QUrl &url);
+
+ static bool isHttpRedirect(int statusCode);
+
#ifndef QT_NO_SSL
QSslConfiguration sslConfiguration() const;
void setSslConfiguration(const QSslConfiguration &config);
@@ -153,6 +160,7 @@ Q_SIGNALS:
void proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *authenticator);
#endif
void authenticationRequired(const QHttpNetworkRequest &request, QAuthenticator *authenticator);
+ void redirected(const QUrl &url, int httpStatus, int maxRedirectsRemaining);
private:
Q_DECLARE_PRIVATE(QHttpNetworkReply)
friend class QHttpSocketEngine;
@@ -185,6 +193,7 @@ public:
qint64 readReplyBodyChunked(QAbstractSocket *in, QByteDataBuffer *out);
qint64 getChunkSize(QAbstractSocket *in, qint64 *chunkSize);
+ bool isRedirecting() const;
bool shouldEmitSignals();
bool expectContent();
void eraseData();
@@ -245,6 +254,7 @@ public:
bool downstreamLimited;
char* userProvidedDownloadBuffer;
+ QUrl redirectUrl;
#ifndef QT_NO_COMPRESS
z_stream_s *inflateStrm;
diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp
index ea1cd3d591..64172fc4fd 100644
--- a/src/network/access/qhttpnetworkrequest.cpp
+++ b/src/network/access/qhttpnetworkrequest.cpp
@@ -42,7 +42,7 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(QHttpNetworkRequest::Oper
QHttpNetworkRequest::Priority pri, const QUrl &newUrl)
: QHttpNetworkHeaderPrivate(newUrl), operation(op), priority(pri), uploadByteDevice(0),
autoDecompress(false), pipeliningAllowed(false), spdyAllowed(false),
- withCredentials(true), preConnect(false)
+ withCredentials(true), preConnect(false), followRedirect(false), redirectCount(0)
{
}
@@ -59,6 +59,8 @@ QHttpNetworkRequestPrivate::QHttpNetworkRequestPrivate(const QHttpNetworkRequest
withCredentials = other.withCredentials;
ssl = other.ssl;
preConnect = other.preConnect;
+ followRedirect = other.followRedirect;
+ redirectCount = other.redirectCount;
}
QHttpNetworkRequestPrivate::~QHttpNetworkRequestPrivate()
@@ -217,6 +219,26 @@ void QHttpNetworkRequest::setPreConnect(bool preConnect)
d->preConnect = preConnect;
}
+bool QHttpNetworkRequest::isFollowRedirects() const
+{
+ return d->followRedirect;
+}
+
+void QHttpNetworkRequest::setFollowRedirects(bool followRedirect)
+{
+ d->followRedirect = followRedirect;
+}
+
+int QHttpNetworkRequest::redirectCount() const
+{
+ return d->redirectCount;
+}
+
+void QHttpNetworkRequest::setRedirectCount(int count)
+{
+ d->redirectCount = count;
+}
+
qint64 QHttpNetworkRequest::contentLength() const
{
return d->contentLength();
diff --git a/src/network/access/qhttpnetworkrequest_p.h b/src/network/access/qhttpnetworkrequest_p.h
index d136f22b7d..1add3c6150 100644
--- a/src/network/access/qhttpnetworkrequest_p.h
+++ b/src/network/access/qhttpnetworkrequest_p.h
@@ -118,6 +118,12 @@ public:
bool isPreConnect() const;
void setPreConnect(bool preConnect);
+ bool isFollowRedirects() const;
+ void setFollowRedirects(bool followRedirect);
+
+ int redirectCount() const;
+ void setRedirectCount(int count);
+
void setUploadByteDevice(QNonContiguousByteDevice *bd);
QNonContiguousByteDevice* uploadByteDevice() const;
@@ -154,6 +160,8 @@ public:
bool withCredentials;
bool ssl;
bool preConnect;
+ bool followRedirect;
+ int redirectCount;
};
diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp
index be6fa01098..3fc4fa9dee 100644
--- a/src/network/access/qhttpthreaddelegate.cpp
+++ b/src/network/access/qhttpthreaddelegate.cpp
@@ -496,6 +496,9 @@ void QHttpThreadDelegate::finishedSlot()
emit error(statusCodeFromHttp(httpReply->statusCode(), httpRequest.url()), msg);
}
+ if (httpRequest.isFollowRedirects() && httpReply->isRedirecting())
+ emit redirected(httpReply->redirectUrl(), httpReply->statusCode(), httpReply->request().redirectCount() - 1);
+
emit downloadFinished();
QMetaObject::invokeMethod(httpReply, "deleteLater", Qt::QueuedConnection);
diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h
index ff919b11c5..4889bcd1f1 100644
--- a/src/network/access/qhttpthreaddelegate_p.h
+++ b/src/network/access/qhttpthreaddelegate_p.h
@@ -139,6 +139,8 @@ signals:
void downloadData(QByteArray);
void error(QNetworkReply::NetworkError, const QString);
void downloadFinished();
+ void redirected(const QUrl &url, int httpStatus, int maxRedirectsRemainig);
+
public slots:
// This are called via QueuedConnection from user thread
void startRequest();
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 3e77e1b874..26f7034c09 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -132,6 +132,14 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
\value BackgroundRequestNotAllowedError the background request
is not currently allowed due to platform policy.
+ \value TooManyRedirectsError while following redirects, the maximum
+ limit was reached. The limit is by default set to 50 or as set by
+ QNetworkRequest::setMaxRedirectsAllowed().
+
+ \value InsecureRedirectError while following redirects, the network
+ access API detected a redirect from a encrypted protocol (https) to an
+ unencrypted one (http).
+
\value ProxyConnectionRefusedError the connection to the proxy
server was refused (the proxy server is not accepting requests)
@@ -276,6 +284,19 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
*/
/*!
+ \fn void QNetworkReply::redirected(const QUrl &url)
+ \since 5.6
+
+ This signal is emitted if the QNetworkRequest::FollowRedirectsAttribute was
+ 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
+ header, indicating a HTTP redirect. The \a url parameter contains the new
+ redirect url as returned by the server in the location header.
+
+ \sa QNetworkRequest::FollowRedirectsAttribute
+*/
+
+/*!
\fn void QNetworkReply::metaDataChanged()
\omit FIXME: Update name? \endomit
@@ -498,7 +519,7 @@ QNetworkAccessManager *QNetworkReply::manager() const
*/
QNetworkRequest QNetworkReply::request() const
{
- return d_func()->request;
+ return d_func()->originalRequest;
}
/*!
@@ -549,9 +570,12 @@ bool QNetworkReply::isRunning() const
/*!
Returns the URL of the content downloaded or uploaded. Note that
- the URL may be different from that of the original request.
+ the URL may be different from that of the original request. If the
+ QNetworkRequest::FollowRedirectsAttribute was set in the request, then this
+ function returns the current url that the network API is accessing, i.e the
+ url emitted in the QNetworkReply::redirected signal.
- \sa request(), setUrl(), QNetworkRequest::url()
+ \sa request(), setUrl(), QNetworkRequest::url(), redirected()
*/
QUrl QNetworkReply::url() const
{
@@ -794,7 +818,7 @@ void QNetworkReply::setOperation(QNetworkAccessManager::Operation operation)
void QNetworkReply::setRequest(const QNetworkRequest &request)
{
Q_D(QNetworkReply);
- d->request = request;
+ d->originalRequest = request;
}
/*!
diff --git a/src/network/access/qnetworkreply.h b/src/network/access/qnetworkreply.h
index 91c9e77d8d..672a69e12b 100644
--- a/src/network/access/qnetworkreply.h
+++ b/src/network/access/qnetworkreply.h
@@ -69,6 +69,8 @@ public:
TemporaryNetworkFailureError,
NetworkSessionFailedError,
BackgroundRequestNotAllowedError,
+ TooManyRedirectsError,
+ InsecureRedirectError,
UnknownNetworkError = 99,
// proxy errors (101-199):
@@ -153,6 +155,7 @@ Q_SIGNALS:
void sslErrors(const QList<QSslError> &errors);
void preSharedKeyAuthenticationRequired(QSslPreSharedKeyAuthenticator *authenticator);
#endif
+ void redirected(const QUrl &url);
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
diff --git a/src/network/access/qnetworkreply_p.h b/src/network/access/qnetworkreply_p.h
index f5fe7bd844..2a3a2e4297 100644
--- a/src/network/access/qnetworkreply_p.h
+++ b/src/network/access/qnetworkreply_p.h
@@ -69,6 +69,7 @@ public:
QNetworkReplyPrivate();
QNetworkRequest request;
+ QNetworkRequest originalRequest;
QUrl url;
QPointer<QNetworkAccessManager> manager;
qint64 readBufferMaxSize;
diff --git a/src/network/access/qnetworkreplyhttpimpl.cpp b/src/network/access/qnetworkreplyhttpimpl.cpp
index c92c360420..47621f41d8 100644
--- a/src/network/access/qnetworkreplyhttpimpl.cpp
+++ b/src/network/access/qnetworkreplyhttpimpl.cpp
@@ -166,6 +166,7 @@ QNetworkReplyHttpImpl::QNetworkReplyHttpImpl(QNetworkAccessManager* const manage
d->manager = manager;
d->managerPrivate = manager->d_func();
d->request = request;
+ d->originalRequest = request;
d->operation = operation;
d->outgoingData = outgoingData;
d->url = request.url();
@@ -482,7 +483,7 @@ bool QNetworkReplyHttpImplPrivate::loadFromCacheIfAllowed(QHttpNetworkRequest &h
if (!nc)
return false; // no local cache
- QNetworkCacheMetaData metaData = nc->metaData(request.url());
+ QNetworkCacheMetaData metaData = nc->metaData(httpRequest.url());
if (!metaData.isValid())
return false; // not in cache
@@ -596,7 +597,7 @@ QHttpNetworkRequest::Priority QNetworkReplyHttpImplPrivate::convert(const QNetwo
}
}
-void QNetworkReplyHttpImplPrivate::postRequest()
+void QNetworkReplyHttpImplPrivate::postRequest(const QNetworkRequest &newHttpRequest)
{
Q_Q(QNetworkReplyHttpImpl);
@@ -620,8 +621,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
thread = managerPrivate->httpThread;
}
- QUrl url = request.url();
+ QUrl url = newHttpRequest.url();
httpRequest.setUrl(url);
+ httpRequest.setRedirectCount(newHttpRequest.maximumRedirectsAllowed());
QString scheme = url.scheme().toLower();
bool ssl = (scheme == QLatin1String("https")
@@ -637,7 +639,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
QNetworkProxy transparentProxy, cacheProxy;
// FIXME the proxy stuff should be done in the HTTP thread
- foreach (const QNetworkProxy &p, managerPrivate->queryProxy(QNetworkProxyQuery(request.url()))) {
+ foreach (const QNetworkProxy &p, managerPrivate->queryProxy(QNetworkProxyQuery(newHttpRequest.url()))) {
// use the first proxy that works
// for non-encrypted connections, any transparent or HTTP proxy
// for encrypted, only transparent proxies
@@ -668,9 +670,11 @@ void QNetworkReplyHttpImplPrivate::postRequest()
}
#endif
+ if (newHttpRequest.attribute(QNetworkRequest::FollowRedirectsAttribute).toBool())
+ httpRequest.setFollowRedirects(true);
bool loadedFromCache = false;
- httpRequest.setPriority(convert(request.priority()));
+ httpRequest.setPriority(convert(newHttpRequest.priority()));
switch (operation) {
case QNetworkAccessManager::GetOperation:
@@ -704,7 +708,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
invalidateCache(); // for safety reasons, we don't know what the operation does
httpRequest.setOperation(QHttpNetworkRequest::Custom);
createUploadByteDevice();
- httpRequest.setCustomVerb(request.attribute(
+ httpRequest.setCustomVerb(newHttpRequest.attribute(
QNetworkRequest::CustomVerbAttribute).toByteArray());
break;
@@ -716,7 +720,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
return; // no need to send the request! :)
}
- QList<QByteArray> headers = request.rawHeaderList();
+ QList<QByteArray> headers = newHttpRequest.rawHeaderList();
if (resumeOffset != 0) {
if (headers.contains("Range")) {
// Need to adjust resume offset for user specified range
@@ -724,7 +728,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
headers.removeOne("Range");
// We've already verified that requestRange starts with "bytes=", see canResume.
- QByteArray requestRange = request.rawHeader("Range").mid(6);
+ QByteArray requestRange = newHttpRequest.rawHeader("Range").mid(6);
int index = requestRange.indexOf('-');
@@ -741,16 +745,16 @@ void QNetworkReplyHttpImplPrivate::postRequest()
}
foreach (const QByteArray &header, headers)
- httpRequest.setHeaderField(header, request.rawHeader(header));
+ httpRequest.setHeaderField(header, newHttpRequest.rawHeader(header));
- if (request.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true)
+ if (newHttpRequest.attribute(QNetworkRequest::HttpPipeliningAllowedAttribute).toBool() == true)
httpRequest.setPipeliningAllowed(true);
if (request.attribute(QNetworkRequest::SpdyAllowedAttribute).toBool() == true)
httpRequest.setSPDYAllowed(true);
if (static_cast<QNetworkRequest::LoadControl>
- (request.attribute(QNetworkRequest::AuthenticationReuseAttribute,
+ (newHttpRequest.attribute(QNetworkRequest::AuthenticationReuseAttribute,
QNetworkRequest::Automatic).toInt()) == QNetworkRequest::Manual)
httpRequest.setWithCredentials(false);
@@ -777,7 +781,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
delegate->ssl = ssl;
#ifndef QT_NO_SSL
if (ssl)
- delegate->incomingSslConfiguration = request.sslConfiguration();
+ delegate->incomingSslConfiguration = newHttpRequest.sslConfiguration();
#endif
// Do we use synchronous HTTP?
@@ -789,7 +793,7 @@ void QNetworkReplyHttpImplPrivate::postRequest()
if (!synchronous) {
// Tell our zerocopy policy to the delegate
- QVariant downloadBufferMaximumSizeAttribute = request.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
+ QVariant downloadBufferMaximumSizeAttribute = newHttpRequest.attribute(QNetworkRequest::MaximumDownloadBufferSizeAttribute);
if (downloadBufferMaximumSizeAttribute.isValid()) {
delegate->downloadBufferMaximumSize = downloadBufferMaximumSizeAttribute.toLongLong();
} else {
@@ -824,6 +828,9 @@ void QNetworkReplyHttpImplPrivate::postRequest()
QObject::connect(delegate, SIGNAL(error(QNetworkReply::NetworkError,QString)),
q, SLOT(httpError(QNetworkReply::NetworkError,QString)),
Qt::QueuedConnection);
+ QObject::connect(delegate, SIGNAL(redirected(QUrl,int,int)),
+ q, SLOT(onRedirected(QUrl,int,int)),
+ Qt::QueuedConnection);
#ifndef QT_NO_SSL
QObject::connect(delegate, SIGNAL(sslConfigurationChanged(QSslConfiguration)),
q, SLOT(replySslConfigurationChanged(QSslConfiguration)),
@@ -950,7 +957,7 @@ void QNetworkReplyHttpImplPrivate::invalidateCache()
{
QAbstractNetworkCache *nc = managerPrivate->networkCache;
if (nc)
- nc->remove(request.url());
+ nc->remove(httpRequest.url());
}
void QNetworkReplyHttpImplPrivate::initCacheSaveDevice()
@@ -1030,21 +1037,30 @@ void QNetworkReplyHttpImplPrivate::replyDownloadData(QByteArray d)
for (int i = 0; i < pendingDownloadDataCopy.bufferCount(); i++) {
QByteArray const &item = pendingDownloadDataCopy[i];
+ // This is going to look a little strange. When downloading data while a
+ // HTTP redirect is happening (and enabled), we write the redirect
+ // response to the cache. However, we do not append it to our internal
+ // buffer as that will contain the response data only for the final
+ // response
if (cacheSaveDevice)
cacheSaveDevice->write(item.constData(), item.size());
- downloadMultiBuffer.append(item);
+
+ if (!isHttpRedirectResponse())
+ downloadMultiBuffer.append(item);
bytesWritten += item.size();
}
pendingDownloadDataCopy.clear();
- bytesDownloaded += bytesWritten;
-
-
QVariant totalSize = cookedHeaders.value(QNetworkRequest::ContentLengthHeader);
if (preMigrationDownloaded != Q_INT64_C(-1))
totalSize = totalSize.toLongLong() + preMigrationDownloaded;
+ if (isHttpRedirectResponse())
+ return;
+
+ bytesDownloaded += bytesWritten;
+
emit q->readyRead();
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
@@ -1066,6 +1082,64 @@ void QNetworkReplyHttpImplPrivate::replyFinished()
finished();
}
+QNetworkAccessManager::Operation QNetworkReplyHttpImplPrivate::getRedirectOperation(QNetworkAccessManager::Operation currentOp, int httpStatus)
+{
+ // HTTP status code can be used to decide if we can redirect with a GET
+ // operation or not. See http://www.ietf.org/rfc/rfc2616.txt [Sec 10.3] for
+ // more details
+ Q_UNUSED(httpStatus);
+
+ switch (currentOp) {
+ case QNetworkAccessManager::HeadOperation:
+ return QNetworkAccessManager::HeadOperation;
+ default:
+ break;
+ }
+ // For now, we're always returning GET for anything other than HEAD
+ return QNetworkAccessManager::GetOperation;
+}
+
+bool QNetworkReplyHttpImplPrivate::isHttpRedirectResponse() const
+{
+ return httpRequest.isFollowRedirects() && QHttpNetworkReply::isHttpRedirect(statusCode);
+}
+
+QNetworkRequest QNetworkReplyHttpImplPrivate::createRedirectRequest(const QNetworkRequest &originalRequest,
+ const QUrl &url,
+ int maxRedirectsRemaining)
+{
+ QNetworkRequest newRequest(originalRequest);
+ newRequest.setUrl(url);
+ newRequest.setMaximumRedirectsAllowed(maxRedirectsRemaining);
+
+ return newRequest;
+}
+
+void QNetworkReplyHttpImplPrivate::onRedirected(const QUrl &redirectUrl, int httpStatus, int maxRedirectsRemaining)
+{
+ Q_Q(QNetworkReplyHttpImpl);
+
+ if (isFinished)
+ return;
+
+ if (httpRequest.isFollowRedirects()) // update the reply's url as it could've changed
+ url = redirectUrl;
+
+ QNetworkRequest redirectRequest = createRedirectRequest(originalRequest, redirectUrl, maxRedirectsRemaining);
+ operation = getRedirectOperation(operation, httpStatus);
+
+ cookedHeaders.clear();
+
+ if (managerPrivate->httpThread)
+ managerPrivate->httpThread->disconnect();
+
+ // Recurse
+ QMetaObject::invokeMethod(q, "start", Qt::QueuedConnection,
+ Q_ARG(QNetworkRequest, redirectRequest));
+
+ emit q->redirected(redirectUrl);
+}
+
void QNetworkReplyHttpImplPrivate::checkForRedirect(const int statusCode)
{
Q_Q(QNetworkReplyHttpImpl);
@@ -1114,7 +1188,16 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData
end = headerMap.constEnd();
for (; it != end; ++it) {
QByteArray value = q->rawHeader(it->first);
+
+ // Reset any previous "location" header set in the reply. In case of
+ // redirects, we don't want to 'append' multiple location header values,
+ // rather we keep only the latest one
+ if (it->first.toLower() == "location")
+ value.clear();
+
if (!value.isEmpty()) {
+ // Why are we appending values for headers which are already
+ // present?
if (qstricmp(it->first.constData(), "set-cookie") == 0)
value += '\n';
else
@@ -1128,12 +1211,13 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData
q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase);
// is it a redirection?
- checkForRedirect(statusCode);
+ if (!isHttpRedirectResponse())
+ checkForRedirect(statusCode);
if (statusCode >= 500 && statusCode < 600) {
QAbstractNetworkCache *nc = managerPrivate->networkCache;
if (nc) {
- QNetworkCacheMetaData metaData = nc->metaData(request.url());
+ QNetworkCacheMetaData metaData = nc->metaData(httpRequest.url());
QNetworkHeadersPrivate cacheHeaders;
cacheHeaders.setAllRawHeaders(metaData.rawHeaders());
QNetworkHeadersPrivate::RawHeadersList::ConstIterator it;
@@ -1155,7 +1239,7 @@ void QNetworkReplyHttpImplPrivate::replyDownloadMetaData
#endif
QAbstractNetworkCache *nc = managerPrivate->networkCache;
if (nc) {
- QNetworkCacheMetaData oldMetaData = nc->metaData(request.url());
+ QNetworkCacheMetaData oldMetaData = nc->metaData(httpRequest.url());
QNetworkCacheMetaData metaData = fetchCacheMetaData(oldMetaData);
if (oldMetaData != metaData)
nc->updateMetaData(metaData);
@@ -1202,6 +1286,9 @@ void QNetworkReplyHttpImplPrivate::replyDownloadProgressSlot(qint64 bytesReceive
// FIXME where is it closed?
}
+ if (isHttpRedirectResponse())
+ return;
+
bytesDownloaded = bytesReceived;
downloadBufferCurrentSize = bytesReceived;
@@ -1350,6 +1437,8 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
if (status < 100)
status = 200; // fake it
+ statusCode = status;
+
q->setAttribute(QNetworkRequest::HttpStatusCodeAttribute, status);
q->setAttribute(QNetworkRequest::HttpReasonPhraseAttribute, attributes.value(QNetworkRequest::HttpReasonPhraseAttribute));
q->setAttribute(QNetworkRequest::SourceIsFromCacheAttribute, true);
@@ -1357,10 +1446,16 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
QNetworkCacheMetaData::RawHeaderList rawHeaders = metaData.rawHeaders();
QNetworkCacheMetaData::RawHeaderList::ConstIterator it = rawHeaders.constBegin(),
end = rawHeaders.constEnd();
- for ( ; it != end; ++it)
+ QUrl redirectUrl;
+ for ( ; it != end; ++it) {
+ if (httpRequest.isFollowRedirects() &&
+ !qstricmp(it->first.toLower().constData(), "location"))
+ redirectUrl = QUrl::fromEncoded(it->second);
setRawHeader(it->first, it->second);
+ }
- checkForRedirect(status);
+ if (!isHttpRedirectResponse())
+ checkForRedirect(status);
cacheLoadDevice = contents;
q->connect(cacheLoadDevice, SIGNAL(readyRead()), SLOT(_q_cacheLoadReadyRead()));
@@ -1377,6 +1472,14 @@ bool QNetworkReplyHttpImplPrivate::sendCacheContents(const QNetworkCacheMetaData
qDebug() << "Successfully sent cache:" << url << contents->size() << "bytes";
#endif
+ // Do redirect processing
+ if (httpRequest.isFollowRedirects() && QHttpNetworkReply::isHttpRedirect(status)) {
+ QMetaObject::invokeMethod(q, "onRedirected", Qt::QueuedConnection,
+ Q_ARG(QUrl, redirectUrl),
+ Q_ARG(int, status),
+ Q_ARG(int, httpRequest.redirectCount() - 1));
+ }
+
// Set the following flag so we can ignore some signals from HTTP thread
// that would still come
loadingFromCache = true;
@@ -1572,13 +1675,13 @@ void QNetworkReplyHttpImplPrivate::setResumeOffset(quint64 offset)
could not be started due to an unopened or roaming session. The caller should recall this
function once the session has been opened or the roaming process has finished.
*/
-bool QNetworkReplyHttpImplPrivate::start()
+bool QNetworkReplyHttpImplPrivate::start(const QNetworkRequest &newHttpRequest)
{
#ifndef QT_NO_BEARERMANAGEMENT
QSharedPointer<QNetworkSession> networkSession(managerPrivate->getNetworkSession());
if (!networkSession) {
#endif
- postRequest();
+ postRequest(newHttpRequest);
return true;
#ifndef QT_NO_BEARERMANAGEMENT
}
@@ -1588,7 +1691,7 @@ bool QNetworkReplyHttpImplPrivate::start()
if (host == QLatin1String("localhost") ||
QHostAddress(host).isLoopback()) {
// Don't need an open session for localhost access.
- postRequest();
+ postRequest(newHttpRequest);
return true;
}
@@ -1597,13 +1700,13 @@ bool QNetworkReplyHttpImplPrivate::start()
Q_Q(QNetworkReplyHttpImpl);
QObject::connect(networkSession.data(), SIGNAL(usagePoliciesChanged(QNetworkSession::UsagePolicies)),
q, SLOT(_q_networkSessionUsagePoliciesChanged(QNetworkSession::UsagePolicies)));
- postRequest();
+ postRequest(newHttpRequest);
return true;
} else if (synchronous) {
// Command line applications using the synchronous path such as xmlpatterns may need an extra push.
networkSession->open();
if (networkSession->waitForOpened()) {
- postRequest();
+ postRequest(newHttpRequest);
return true;
}
}
@@ -1635,7 +1738,7 @@ void QNetworkReplyHttpImplPrivate::_q_startOperation()
}
#endif
- if (!start()) {
+ if (!start(request)) {
#ifndef QT_NO_BEARERMANAGEMENT
// backend failed to start because the session state is not Connected.
// QNetworkAccessManager will call reply->backend->start() again for us when the session
@@ -1697,18 +1800,20 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead()
// emit readyRead before downloadProgress incase this will cause events to be
// processed and we get into a recursive call (as in QProgressDialog).
- // This readyRead() goes to the user. The user then may or may not read() anything.
- emit q->readyRead();
- if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
- downloadProgressSignalChoke.restart();
- emit q->downloadProgress(bytesDownloaded,
- totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
- }
+ if (!(isHttpRedirectResponse())) {
+ // This readyRead() goes to the user. The user then may or may not read() anything.
+ emit q->readyRead();
+ if (downloadProgressSignalChoke.elapsed() >= progressSignalInterval) {
+ downloadProgressSignalChoke.restart();
+ emit q->downloadProgress(bytesDownloaded,
+ totalSize.isNull() ? Q_INT64_C(-1) : totalSize.toLongLong());
+ }
+ }
// If there are still bytes available in the cacheLoadDevice then the user did not read
// in response to the readyRead() signal. This means we have to load from the cacheLoadDevice
// and buffer that stuff. This is needed to be able to properly emit finished() later.
- while (cacheLoadDevice->bytesAvailable()) {
+ while (cacheLoadDevice->bytesAvailable() && !isHttpRedirectResponse()) {
downloadMultiBuffer.append(cacheLoadDevice->readAll());
}
@@ -1731,7 +1836,6 @@ void QNetworkReplyHttpImplPrivate::_q_cacheLoadReadyRead()
cacheLoadDevice = 0;
QMetaObject::invokeMethod(q, "_q_finished", Qt::QueuedConnection);
}
-
}
@@ -1951,6 +2055,15 @@ void QNetworkReplyHttpImplPrivate::finished()
#endif
}
+ // if we don't know the total size of or we received everything save the cache
+ if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
+ completeCacheSave();
+
+ // We check for errorCode too as in case of SSL handshake failure, we still
+ // get the HTTP redirect status code (301, 303 etc)
+ if (isHttpRedirectResponse() && errorCode == QNetworkReply::NoError)
+ return;
+
state = Finished;
q->setFinished(true);
@@ -1963,10 +2076,6 @@ void QNetworkReplyHttpImplPrivate::finished()
if (bytesUploaded == -1 && (outgoingData || outgoingDataBuffer))
emit q->uploadProgress(0, 0);
- // if we don't know the total size of or we received everything save the cache
- if (totalSize.isNull() || totalSize == -1 || bytesDownloaded == totalSize)
- completeCacheSave();
-
emit q->readChannelFinished();
emit q->finished();
}
diff --git a/src/network/access/qnetworkreplyhttpimpl_p.h b/src/network/access/qnetworkreplyhttpimpl_p.h
index afe807ea59..08f3fcf342 100644
--- a/src/network/access/qnetworkreplyhttpimpl_p.h
+++ b/src/network/access/qnetworkreplyhttpimpl_p.h
@@ -89,6 +89,7 @@ public:
Q_DECLARE_PRIVATE(QNetworkReplyHttpImpl)
Q_PRIVATE_SLOT(d_func(), void _q_startOperation())
+ Q_PRIVATE_SLOT(d_func(), bool start(const QNetworkRequest &))
Q_PRIVATE_SLOT(d_func(), void _q_cacheLoadReadyRead())
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingData())
Q_PRIVATE_SLOT(d_func(), void _q_bufferOutgoingDataFinished())
@@ -126,7 +127,7 @@ public:
Q_PRIVATE_SLOT(d_func(), void emitReplyUploadProgress(qint64, qint64))
Q_PRIVATE_SLOT(d_func(), void _q_cacheSaveDeviceAboutToClose())
Q_PRIVATE_SLOT(d_func(), void _q_metaDataChanged())
-
+ Q_PRIVATE_SLOT(d_func(), void onRedirected(const QUrl &, int, int))
#ifndef QT_NO_SSL
protected:
@@ -157,7 +158,7 @@ public:
QNetworkReplyHttpImplPrivate();
~QNetworkReplyHttpImplPrivate();
- bool start();
+ bool start(const QNetworkRequest &newHttpRequest);
void _q_startOperation();
void _q_cacheLoadReadyRead();
@@ -200,6 +201,7 @@ public:
QIODevice *outgoingData;
QSharedPointer<QRingBuffer> outgoingDataBuffer;
void emitReplyUploadProgress(qint64 bytesSent, qint64 bytesTotal); // dup?
+ void onRedirected(const QUrl &redirectUrl, int httpStatus, int maxRedirectsRemainig);
qint64 bytesUploaded;
@@ -259,9 +261,10 @@ public:
QNetworkCacheMetaData fetchCacheMetaData(const QNetworkCacheMetaData &metaData) const;
- void postRequest();
-
-
+ void postRequest(const QNetworkRequest& newHttpRequest);
+ QNetworkAccessManager::Operation getRedirectOperation(QNetworkAccessManager::Operation currentOp, int httpStatus);
+ QNetworkRequest createRedirectRequest(const QNetworkRequest &originalRequests, const QUrl &url, int maxRedirectsRemainig);
+ bool isHttpRedirectResponse() const;
public:
// From HTTP thread:
diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp
index bcfa48e666..be1adfbee1 100644
--- a/src/network/access/qnetworkreplyimpl.cpp
+++ b/src/network/access/qnetworkreplyimpl.cpp
@@ -923,13 +923,11 @@ void QNetworkReplyImpl::abort()
QNetworkReply::close();
- if (d->state != QNetworkReplyPrivate::Finished) {
- // call finished which will emit signals
- d->error(OperationCanceledError, tr("Operation canceled"));
- if (d->state == QNetworkReplyPrivate::WaitingForSession)
- d->state = QNetworkReplyPrivate::Working;
- d->finished();
- }
+ // call finished which will emit signals
+ d->error(OperationCanceledError, tr("Operation canceled"));
+ if (d->state == QNetworkReplyPrivate::WaitingForSession)
+ d->state = QNetworkReplyPrivate::Working;
+ d->finished();
d->state = QNetworkReplyPrivate::Aborted;
// finished may access the backend
diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp
index c7cb16c71c..94e2b437b3 100644
--- a/src/network/access/qnetworkrequest.cpp
+++ b/src/network/access/qnetworkrequest.cpp
@@ -140,7 +140,9 @@ QT_BEGIN_NAMESPACE
request to a different URL. The Network Access API does not by
default follow redirections: it's up to the application to
determine if the requested redirection should be allowed,
- according to its security policies.
+ according to its security policies. However, if
+ QNetworkRequest::FollowRedirectsAttribute is set, then this attribute
+ will not be present in the reply.
The returned URL might be relative. Use QUrl::resolved()
to create an absolute URL out of it.
@@ -256,6 +258,12 @@ QT_BEGIN_NAMESPACE
in 100 millisecond intervals.
(This value was introduced in 5.5.)
+ \value FollowRedirectsAttribute
+ Requests only, type: QMetaType::Bool (default: false)
+ Indicates whether the Network Access API should automatically follow a
+ HTTP redirect response or not. Currently redirects that are insecure,
+ that is redirecting from "https" to "http" protocol, are not allowed.
+
\value User
Special type. Additional information can be passed in
QVariants with types ranging from User to UserMax. The default
@@ -306,11 +314,13 @@ QT_BEGIN_NAMESPACE
class QNetworkRequestPrivate: public QSharedData, public QNetworkHeadersPrivate
{
public:
+ static const int maxRedirectCount = 50;
inline QNetworkRequestPrivate()
: priority(QNetworkRequest::NormalPriority)
#ifndef QT_NO_SSL
, sslConfiguration(0)
#endif
+ , maxRedirectsAllowed(maxRedirectCount)
{ qRegisterMetaType<QNetworkRequest>(); }
~QNetworkRequestPrivate()
{
@@ -325,7 +335,7 @@ public:
{
url = other.url;
priority = other.priority;
-
+ maxRedirectsAllowed = other.maxRedirectsAllowed;
#ifndef QT_NO_SSL
sslConfiguration = 0;
if (other.sslConfiguration)
@@ -338,7 +348,8 @@ public:
return url == other.url &&
priority == other.priority &&
rawHeaders == other.rawHeaders &&
- attributes == other.attributes;
+ attributes == other.attributes &&
+ maxRedirectsAllowed == other.maxRedirectsAllowed;
// don't compare cookedHeaders
}
@@ -347,6 +358,7 @@ public:
#ifndef QT_NO_SSL
mutable QSslConfiguration *sslConfiguration;
#endif
+ int maxRedirectsAllowed;
};
/*!
@@ -657,6 +669,32 @@ void QNetworkRequest::setPriority(Priority priority)
d->priority = priority;
}
+/*!
+ \since 5.6
+
+ Returns the maximum number of redirects allowed to be followed for this
+ request.
+
+ \sa setMaximumRedirectsAllowed()
+*/
+int QNetworkRequest::maximumRedirectsAllowed() const
+{
+ return d->maxRedirectsAllowed;
+}
+
+/*!
+ \since 5.6
+
+ Sets the maximum number of redirects allowed to be followed for this
+ request to \a maxRedirectsAllowed.
+
+ \sa maximumRedirectsAllowed()
+*/
+void QNetworkRequest::setMaximumRedirectsAllowed(int maxRedirectsAllowed)
+{
+ d->maxRedirectsAllowed = maxRedirectsAllowed;
+}
+
static QByteArray headerName(QNetworkRequest::KnownHeaders header)
{
switch (header) {
diff --git a/src/network/access/qnetworkrequest.h b/src/network/access/qnetworkrequest.h
index d6d907bdc4..c726db78cb 100644
--- a/src/network/access/qnetworkrequest.h
+++ b/src/network/access/qnetworkrequest.h
@@ -81,6 +81,7 @@ public:
SpdyAllowedAttribute,
SpdyWasUsedAttribute,
EmitAllUploadProgressSignalsAttribute,
+ FollowRedirectsAttribute,
User = 1000,
UserMax = 32767
@@ -141,6 +142,10 @@ public:
Priority priority() const;
void setPriority(Priority priority);
+ // HTTP redirect related
+ int maximumRedirectsAllowed() const;
+ void setMaximumRedirectsAllowed(int maximumRedirectsAllowed);
+
private:
QSharedDataPointer<QNetworkRequestPrivate> d;
friend class QNetworkRequestPrivate;
diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp
index 3b10387b37..f94b1edbff 100644
--- a/src/network/socket/qabstractsocket.cpp
+++ b/src/network/socket/qabstractsocket.cpp
@@ -812,7 +812,7 @@ bool QAbstractSocketPrivate::canWriteNotification()
#if defined (QABSTRACTSOCKET_DEBUG)
qDebug("QAbstractSocketPrivate::canWriteNotification() flushing");
#endif
- int tmp = writeBuffer.size();
+ qint64 tmp = writeBuffer.size();
flush();
if (socketEngine) {
@@ -872,7 +872,7 @@ bool QAbstractSocketPrivate::flush()
return false;
}
- int nextSize = writeBuffer.nextDataBlockSize();
+ qint64 nextSize = writeBuffer.nextDataBlockSize();
const char *ptr = writeBuffer.readPointer();
// Attempt to write it all in one chunk.
@@ -1707,9 +1707,9 @@ qint64 QAbstractSocket::bytesToWrite() const
{
Q_D(const QAbstractSocket);
#if defined(QABSTRACTSOCKET_DEBUG)
- qDebug("QAbstractSocket::bytesToWrite() == %i", d->writeBuffer.size());
+ qDebug("QAbstractSocket::bytesToWrite() == %lld", d->writeBuffer.size());
#endif
- return (qint64)d->writeBuffer.size();
+ return d->writeBuffer.size();
}
/*!
diff --git a/src/platformheaders/xcbfunctions/qxcbfunctionshelper.h b/src/platformheaders/xcbfunctions/qxcbfunctionshelper.h
new file mode 100644
index 0000000000..a9d734a387
--- /dev/null
+++ b/src/platformheaders/xcbfunctions/qxcbfunctionshelper.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBFUNCTIONHELPER_H
+#define QXCBFUNCTIONHELPER_H
+
+#include <QtCore/QByteArray>
+#include <QtGui/QGuiApplication>
+
+QT_BEGIN_NAMESPACE
+
+namespace QXcbFunctionsHelper
+{
+
+template<typename ReturnT, typename FunctionT>
+ReturnT callPlatformFunction(const QByteArray &functionName)
+{
+ FunctionT func = reinterpret_cast<FunctionT>(QGuiApplication::platformFunction(functionName));
+ return func ? func() : ReturnT();
+}
+
+template<typename ReturnT, typename FunctionT, typename Arg1>
+ReturnT callPlatformFunction(const QByteArray &functionName, Arg1 a1)
+{
+ FunctionT func = reinterpret_cast<FunctionT>(QGuiApplication::platformFunction(functionName));
+ return func ? func(a1) : ReturnT();
+}
+
+template<typename ReturnT, typename FunctionT, typename Arg1, typename Arg2>
+ReturnT callPlatformFunction(const QByteArray &functionName, Arg1 a1, Arg2 a2)
+{
+ FunctionT func = reinterpret_cast<FunctionT>(QGuiApplication::platformFunction(functionName));
+ return func ? func(a1, a2) : ReturnT();
+}
+
+template<typename ReturnT, typename FunctionT, typename Arg1, typename Arg2, typename Arg3>
+ReturnT callPlatformFunction(const QByteArray &functionName, Arg1 a1, Arg2 a2, Arg3 a3)
+{
+ FunctionT func = reinterpret_cast<FunctionT>(QGuiApplication::platformFunction(functionName));
+ return func ? func(a1, a2, a3) : ReturnT();
+}
+
+template<typename ReturnT, typename FunctionT, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ReturnT callPlatformFunction(const QByteArray &functionName, Arg1 a1, Arg2 a2, Arg3 a3, Arg4 a4)
+{
+ FunctionT func = reinterpret_cast<FunctionT>(QGuiApplication::platformFunction(functionName));
+ return func ? func(a1, a2, a3, a4) : ReturnT();
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif /*QXCBFUNCTIONHELPER_H*/
diff --git a/src/platformheaders/xcbfunctions/qxcbintegrationfunctions.h b/src/platformheaders/xcbfunctions/qxcbintegrationfunctions.h
new file mode 100644
index 0000000000..87e19e6a45
--- /dev/null
+++ b/src/platformheaders/xcbfunctions/qxcbintegrationfunctions.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL21$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 or version 3 as published by the Free
+** Software Foundation and appearing in the file LICENSE.LGPLv21 and
+** LICENSE.LGPLv3 included in the packaging of this file. Please review the
+** following information to ensure the GNU Lesser General Public License
+** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QXCBINTEGRATIONFUNCTIONS_H
+#define QXCBINTEGRATIONFUNCTIONS_H
+
+#include "qxcbfunctionshelper.h"
+
+QT_BEGIN_NAMESPACE
+
+class QXcbIntegrationFunctions
+{
+public:
+ typedef bool (*XEmbedSystemTrayVisualHasAlphaChannel)();
+ static const QByteArray xEmbedSystemTrayVisualHasAlphaChannelIdentifier() { return QByteArrayLiteral("XcbXEmbedSystemTrayVisualHasAlphaChannel"); }
+ static bool xEmbedSystemTrayVisualHasAlphaChannel()
+ {
+ return QXcbFunctionsHelper::callPlatformFunction<bool, XEmbedSystemTrayVisualHasAlphaChannel>(xEmbedSystemTrayVisualHasAlphaChannelIdentifier());
+ }
+};
+
+QT_END_NAMESPACE
+
+#endif /*QXCBINTEGRATIONFUNCTIONS_H*/
diff --git a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h
index f9008039a1..accd64f170 100644
--- a/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h
+++ b/src/platformheaders/xcbfunctions/qxcbwindowfunctions.h
@@ -34,8 +34,7 @@
#ifndef QXCBWINDOWFUNCTIONS_H
#define QXCBWINDOWFUNCTIONS_H
-#include <QtCore/QByteArray>
-#include <QtGui/QGuiApplication>
+#include "qxcbfunctionshelper.h"
QT_BEGIN_NAMESPACE
@@ -65,12 +64,37 @@ public:
typedef void (*SetWmWindowType)(QWindow *window, QXcbWindowFunctions::WmWindowTypes windowType);
static const QByteArray setWmWindowTypeIdentifier() { return QByteArrayLiteral("XcbSetWmWindowType"); }
-
static void setWmWindowType(QWindow *window, WmWindowType type)
{
- SetWmWindowType func = reinterpret_cast<SetWmWindowType>(QGuiApplication::platformFunction(setWmWindowTypeIdentifier()));
- if (func)
- func(window, type);
+ return QXcbFunctionsHelper::callPlatformFunction<void, SetWmWindowType, QWindow *, WmWindowType>(setWmWindowTypeIdentifier(), window, type);
+ }
+
+ typedef void (*SetWmWindowIconText)(QWindow *window, const QString &text);
+ static const QByteArray setWmWindowIconTextIdentifier() { return QByteArrayLiteral("XcbSetWmWindowIconText"); }
+ static void setWmWindowIconText(QWindow *window, const QString &text)
+ {
+ return QXcbFunctionsHelper::callPlatformFunction<void, SetWmWindowIconText, QWindow *, const QString &>(setWmWindowIconTextIdentifier(), window, text);
+ }
+
+ typedef void (*SetParentRelativeBackPixmap)(const QWindow *window);
+ static const QByteArray setParentRelativeBackPixmapIdentifier() { return QByteArrayLiteral("XcbSetParentRelativeBackPixmap"); }
+ static void setParentRelativeBackPixmap(const QWindow *window)
+ {
+ return QXcbFunctionsHelper::callPlatformFunction<void, SetParentRelativeBackPixmap, const QWindow *>(setParentRelativeBackPixmapIdentifier(), window);
+ }
+
+ typedef bool (*RequestSystemTrayWindowDock)(const QWindow *window);
+ static const QByteArray requestSystemTrayWindowDockIdentifier() { return QByteArrayLiteral("XcbRequestSystemTrayWindowDockIdentifier"); }
+ static bool requestSystemTrayWindowDock(const QWindow *window)
+ {
+ return QXcbFunctionsHelper::callPlatformFunction<bool, RequestSystemTrayWindowDock, const QWindow *>(requestSystemTrayWindowDockIdentifier(), window);
+ }
+
+ typedef QRect (*SystemTrayWindowGlobalGeometry)(const QWindow *window);
+ static const QByteArray systemTrayWindowGlobalGeometryIdentifier() { return QByteArrayLiteral("XcbSystemTrayWindowGlobalGeometryIdentifier"); }
+ static QRect systemTrayWindowGlobalGeometry(const QWindow *window)
+ {
+ return QXcbFunctionsHelper::callPlatformFunction<QRect, SystemTrayWindowGlobalGeometry, const QWindow *>(systemTrayWindowGlobalGeometryIdentifier(), window);
}
};
diff --git a/src/platformheaders/xcbfunctions/xcbfunctions.pri b/src/platformheaders/xcbfunctions/xcbfunctions.pri
index 8844913cd1..7f611d80bd 100644
--- a/src/platformheaders/xcbfunctions/xcbfunctions.pri
+++ b/src/platformheaders/xcbfunctions/xcbfunctions.pri
@@ -1 +1,3 @@
-HEADERS += $$PWD/qxcbwindowfunctions.h
+HEADERS += \
+ $$PWD/qxcbwindowfunctions.h \
+ $$PWD/qxcbintegrationfunctions.h
diff --git a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
index 345fb5e2fa..c040dab5e1 100644
--- a/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
+++ b/src/platformsupport/linuxaccessibility/atspiadaptor.cpp
@@ -1924,6 +1924,124 @@ QAccessible::TextBoundaryType AtSpiAdaptor::qAccessibleBoundaryType(int atspiTex
return QAccessible::CharBoundary;
}
+namespace
+{
+ struct AtSpiAttribute {
+ QString name;
+ QString value;
+ AtSpiAttribute(const QString &aName, const QString &aValue) : name(aName), value(aValue) {}
+ bool isNull() const { return name.isNull() || value.isNull(); }
+ };
+
+ QString atspiColor(const QString &ia2Color)
+ {
+ // "rgb(%u,%u,%u)" -> "%u,%u,%u"
+ return ia2Color.mid(4, ia2Color.length() - (4+1));
+ }
+
+ QString atspiSize(const QString &ia2Size)
+ {
+ // "%fpt" -> "%f"
+ return ia2Size.left(ia2Size.length() - 2);
+ }
+
+ AtSpiAttribute atspiTextAttribute(const QString &ia2Name, const QString &ia2Value)
+ {
+ QString name = ia2Name;
+ QString value = ia2Value;
+
+ // IAccessible2: http://www.linuxfoundation.org/collaborate/workgroups/accessibility/iaccessible2/textattributes
+ // ATK attribute names: https://git.gnome.org/browse/orca/tree/src/orca/text_attribute_names.py
+ // ATK attribute values: https://developer.gnome.org/atk/unstable/AtkText.html#AtkTextAttribute
+
+ // https://bugzilla.gnome.org/show_bug.cgi?id=744553 "ATK docs provide no guidance for allowed values of some text attributes"
+ // specifically for "weight", "invalid", "language" and value range for colors
+
+ if (ia2Name == QStringLiteral("background-color")) {
+ name = QStringLiteral("bg-color");
+ value = atspiColor(value);
+ } else if (ia2Name == QStringLiteral("font-family")) {
+ name = QStringLiteral("family-name");
+ } else if (ia2Name == QStringLiteral("color")) {
+ name = QStringLiteral("fg-color");
+ value = atspiColor(value);
+ } else if (ia2Name == QStringLiteral("text-align")) {
+ name = QStringLiteral("justification");
+ if (value == QStringLiteral("justify")) {
+ value = QStringLiteral("fill");
+ } else {
+ if (value != QStringLiteral("left") &&
+ value != QStringLiteral("right") &&
+ value != QStringLiteral("center")
+ ) {
+ value = QString();
+ qAtspiDebug() << "Unknown text-align attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ }
+ } else if (ia2Name == QStringLiteral("font-size")) {
+ name = QStringLiteral("size");
+ value = atspiSize(value);
+ } else if (ia2Name == QStringLiteral("font-style")) {
+ name = QStringLiteral("style");
+ if (value != QStringLiteral("normal") &&
+ value != QStringLiteral("italic") &&
+ value != QStringLiteral("oblique")
+ ) {
+ value = QString();
+ qAtspiDebug() << "Unknown font-style attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QStringLiteral("text-underline-type")) {
+ name = QStringLiteral("underline");
+ if (value != QStringLiteral("none") &&
+ value != QStringLiteral("single") &&
+ value != QStringLiteral("double")
+ ) {
+ value = QString();
+ qAtspiDebug() << "Unknown text-underline-type attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QStringLiteral("font-weight")) {
+ name = QStringLiteral("weight");
+ if (value == QStringLiteral("normal"))
+ // Orca seems to accept all IAccessible2 values except for "normal"
+ // (on which it produces traceback and fails to read any following text attributes),
+ // but that is the default value, so omit it anyway
+ value = QString();
+ } else if (ia2Name == QStringLiteral("text-position")) {
+ name = QStringLiteral("vertical-align");
+ if (value != QStringLiteral("baseline") &&
+ value != QStringLiteral("super") &&
+ value != QStringLiteral("sub")
+ ) {
+ value = QString();
+ qAtspiDebug() << "Unknown text-position attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QStringLiteral("writing-mode")) {
+ name = QStringLiteral("direction");
+ if (value == QStringLiteral("lr"))
+ value = QStringLiteral("ltr");
+ else if (value == QStringLiteral("rl"))
+ value = QStringLiteral("rtl");
+ else if (value == QStringLiteral("tb")) {
+ // IAccessible2 docs refer to XSL, which specifies "tb" is shorthand for "tb-rl"; so at least give a hint about the horizontal direction (ATK does not support vertical direction in this attribute (yet))
+ value = QStringLiteral("rtl");
+ qAtspiDebug() << "writing-mode attribute value \"tb\" translated only w.r.t. horizontal direction; vertical direction ignored";
+ } else {
+ value = QString();
+ qAtspiDebug() << "Unknown writing-mode attribute value \"" << value << "\" cannot be translated to AT-SPI.";
+ }
+ } else if (ia2Name == QStringLiteral("language")) {
+ // OK - ATK has no docs on the format of the value, IAccessible2 has reasonable format - leave it at that now
+ } else if (ia2Name == QStringLiteral("invalid")) {
+ // OK - ATK docs are vague but suggest they support the same range of values as IAccessible2
+ } else {
+ // attribute we know nothing about
+ name = QString();
+ value = QString();
+ }
+ return AtSpiAttribute(name, value);
+ }
+}
+
// FIXME all attribute methods below should share code
QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int offset, bool includeDefaults) const
{
@@ -1938,7 +2056,9 @@ QVariantList AtSpiAdaptor::getAttributes(QAccessibleInterface *interface, int of
foreach (const QString &attr, attributes) {
QStringList items;
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
- set[items[0]] = items[1];
+ AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
+ if (!attribute.isNull())
+ set[attribute.name] = attribute.value;
}
QVariantList list;
@@ -1962,7 +2082,9 @@ QVariantList AtSpiAdaptor::getAttributeValue(QAccessibleInterface *interface, in
foreach (const QString& attr, attributes) {
QStringList items;
items = attr.split(QLatin1Char(':'), QString::SkipEmptyParts, Qt::CaseSensitive);
- map[items[0]] = items[1];
+ AtSpiAttribute attribute = atspiTextAttribute(items[0], items[1]);
+ if (!attribute.isNull())
+ map[attribute.name] = attribute.value;
}
mapped = map[attributeName];
defined = mapped.isEmpty();
diff --git a/src/platformsupport/linuxaccessibility/dbusconnection.cpp b/src/platformsupport/linuxaccessibility/dbusconnection.cpp
index 45729fa065..637b06549a 100644
--- a/src/platformsupport/linuxaccessibility/dbusconnection.cpp
+++ b/src/platformsupport/linuxaccessibility/dbusconnection.cpp
@@ -42,6 +42,9 @@
#include <QDBusConnectionInterface>
#include "bus_interface.h"
+#include <QtGui/qguiapplication.h>
+#include <qplatformnativeinterface.h>
+
QT_BEGIN_NAMESPACE
QString A11Y_SERVICE = QStringLiteral("org.a11y.Bus");
@@ -65,6 +68,29 @@ DBusConnection::DBusConnection(QObject *parent)
// If it is registered already, setup a11y right away
if (c.interface()->isServiceRegistered(A11Y_SERVICE))
serviceRegistered();
+
+ // In addition try if there is an xatom exposing the bus address, this allows applications run as root to work
+ QString address = getAddressFromXCB();
+ if (!address.isEmpty()) {
+ m_enabled = true;
+ connectA11yBus(address);
+ }
+}
+
+QString DBusConnection::getAddressFromXCB()
+{
+ QGuiApplication *app = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
+ if (!app)
+ return QString();
+ QPlatformNativeInterface *platformNativeInterface = app->platformNativeInterface();
+ QByteArray *addressByteArray = reinterpret_cast<QByteArray*>(
+ platformNativeInterface->nativeResourceForIntegration(QByteArrayLiteral("AtspiBus")));
+ if (addressByteArray) {
+ QString address = QString::fromLatin1(*addressByteArray);
+ delete addressByteArray;
+ return address;
+ }
+ return QString();
}
// We have the a11y registry on the session bus.
diff --git a/src/platformsupport/linuxaccessibility/dbusconnection_p.h b/src/platformsupport/linuxaccessibility/dbusconnection_p.h
index a0bd6450bf..30707a3f95 100644
--- a/src/platformsupport/linuxaccessibility/dbusconnection_p.h
+++ b/src/platformsupport/linuxaccessibility/dbusconnection_p.h
@@ -68,6 +68,7 @@ Q_SIGNALS:
void enabledChanged(bool enabled);
private Q_SLOTS:
+ QString getAddressFromXCB();
void serviceRegistered();
void serviceUnregistered();
void connectA11yBus(const QString &address);
diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
index e887a4ebdc..47018bfece 100644
--- a/src/plugins/platforms/android/androidjnimain.cpp
+++ b/src/plugins/platforms/android/androidjnimain.cpp
@@ -594,6 +594,11 @@ static void updateApplicationState(JNIEnv */*env*/, jobject /*thiz*/, jint state
return;
}
+ if (state == Qt::ApplicationActive)
+ QtAndroidPrivate::handleResume();
+ else if (state == Qt::ApplicationInactive)
+ QtAndroidPrivate::handlePause();
+
if (state <= Qt::ApplicationInactive) {
// Don't send timers and sockets events anymore if we are going to hide all windows
QAndroidEventDispatcherStopper::instance()->goingToStop(true);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.h b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
index d232298396..061dfac156 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.h
@@ -77,7 +77,7 @@ bool shouldBeIgnored(QAccessibleInterface *interface);
NSArray *unignoredChildren(QAccessibleInterface *interface);
NSString *getTranslatedAction(const QString &qtAction);
NSMutableArray *createTranslatedActionsList(const QStringList &qtActions);
-QString translateAction(NSString *nsAction);
+QString translateAction(NSString *nsAction, QAccessibleInterface *interface);
bool hasValueAttribute(QAccessibleInterface *interface);
id getValueAttribute(QAccessibleInterface *interface);
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 0107d7a673..03f585d19d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -284,6 +284,8 @@ NSString *getTranslatedAction(const QString &qtAction)
return NSAccessibilityShowMenuAction;
else if (qtAction == QAccessibleActionInterface::setFocusAction()) // Not 100% sure on this one
return NSAccessibilityRaiseAction;
+ else if (qtAction == QAccessibleActionInterface::toggleAction())
+ return NSAccessibilityPressAction;
// Not translated:
//
@@ -305,11 +307,13 @@ NSString *getTranslatedAction(const QString &qtAction)
Translates between a Mac action constant and a QAccessibleActionInterface action
Returns an empty QString if there is no Qt predefined equivalent.
*/
-QString translateAction(NSString *nsAction)
+QString translateAction(NSString *nsAction, QAccessibleInterface *interface)
{
- if ([nsAction compare: NSAccessibilityPressAction] == NSOrderedSame)
+ if ([nsAction compare: NSAccessibilityPressAction] == NSOrderedSame) {
+ if (interface->role() == QAccessible::CheckBox || interface->role() == QAccessible::RadioButton)
+ return QAccessibleActionInterface::toggleAction();
return QAccessibleActionInterface::pressAction();
- else if ([nsAction compare: NSAccessibilityIncrementAction] == NSOrderedSame)
+ } else if ([nsAction compare: NSAccessibilityIncrementAction] == NSOrderedSame)
return QAccessibleActionInterface::increaseAction();
else if ([nsAction compare: NSAccessibilityDecrementAction] == NSOrderedSame)
return QAccessibleActionInterface::decreaseAction();
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index cf82c9cb37..84d60df3ef 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -501,7 +501,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (!iface)
return nil; // FIXME is that the right return type??
- QString qtAction = QCocoaAccessible::translateAction(action);
+ QString qtAction = QCocoaAccessible::translateAction(action, iface);
QString description;
// Return a description from the action interface if this action is not known to the OS.
if (qtAction.isEmpty()) {
@@ -518,7 +518,7 @@ static void convertLineOffset(QAccessibleTextInterface *text, int &line, int &of
- (void)accessibilityPerformAction:(NSString *)action {
QAccessibleInterface *iface = QAccessible::accessibleInterface(axid);
if (iface) {
- const QString qtAction = QCocoaAccessible::translateAction(action);
+ const QString qtAction = QCocoaAccessible::translateAction(action, iface);
QAccessibleBridgeUtils::performEffectiveAction(iface, qtAction);
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 4064f31cd7..fba97c2629 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -269,6 +269,7 @@ public: // for QNSView
bool m_inConstructor;
bool m_inSetVisible;
bool m_inSetGeometry;
+ bool m_inSetStyleMask;
#ifndef QT_NO_OPENGL
QCocoaGLContext *m_glContext;
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index f811bd630f..6c90e99238 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -375,6 +375,7 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw)
, m_inConstructor(true)
, m_inSetVisible(false)
, m_inSetGeometry(false)
+ , m_inSetStyleMask(false)
#ifndef QT_NO_OPENGL
, m_glContext(0)
#endif
@@ -880,10 +881,14 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
if (m_nsWindow && !m_isNSWindowChild) {
NSUInteger styleMask = windowStyleMask(flags);
NSInteger level = this->windowLevel(flags);
+ // While setting style mask we can have -updateGeometry calls on a content
+ // view with null geometry, reporting an invalid coordinates as a result.
+ m_inSetStyleMask = true;
[m_nsWindow setStyleMask:styleMask];
+ m_inSetStyleMask = false;
[m_nsWindow setLevel:level];
setWindowShadow(flags);
- if (!(styleMask & NSBorderlessWindowMask)) {
+ if (!(flags & Qt::FramelessWindowHint)) {
setWindowTitle(window()->title());
}
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 0b0dcc4322..fd989cb840 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -345,6 +345,12 @@ static NSString *_q_NSWindowDidChangeOcclusionStateNotification = nil;
if (m_platformWindow->m_nsWindow && geometry == m_platformWindow->geometry())
return;
+ // It can happen that self.window is nil (if we are changing
+ // styleMask from/to borderless and content view is being re-parented)
+ // - this results in an invalid coordinates.
+ if (m_platformWindow->m_inSetStyleMask && !self.window)
+ return;
+
#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
qDebug() << "QNSView::udpateGeometry" << m_platformWindow << geometry;
#endif
diff --git a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
index 0caec50c94..2bc9c00a94 100644
--- a/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/gl_integrations/xcb_glx/qglxintegration.cpp
@@ -188,16 +188,18 @@ void QGLXContext::init(QXcbScreen *screen, QPlatformOpenGLContext *share)
Window window = 0; // Temporary window used to query OpenGL context
if (config) {
+ const QByteArrayList glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' ');
+
// Resolve entry point for glXCreateContextAttribsARB
glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0;
- glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
+ if (glxExt.contains("GLX_ARB_create_context"))
+ glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
- QList<QByteArray> glxExt = QByteArray(glXQueryExtensionsString(m_display, screen->screenNumber())).split(' ');
- bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
+ const bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
// Use glXCreateContextAttribsARB if available
// Also, GL ES context creation requires GLX_EXT_create_context_es2_profile
- if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0
+ if (glXCreateContextAttribsARB != 0
&& (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
// Try to create an OpenGL context for each known OpenGL version in descending
// order from the requested version.
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 3b3fcd0b49..0ca141526e 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1956,10 +1956,11 @@ bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *ev, int opCo
}
#endif // defined(XCB_USE_XINPUT2)
-QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker()
+QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const
{
if (!m_systemTrayTracker) {
- if ( (m_systemTrayTracker = QXcbSystemTrayTracker::create(this)) ) {
+ QXcbConnection *self = const_cast<QXcbConnection *>(this);
+ if ((self->m_systemTrayTracker = QXcbSystemTrayTracker::create(self))) {
connect(m_systemTrayTracker, SIGNAL(systemTrayWindowChanged(QScreen*)),
QGuiApplication::platformNativeInterface(), SIGNAL(systemTrayWindowChanged(QScreen*)));
}
@@ -1967,6 +1968,22 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker()
return m_systemTrayTracker;
}
+bool QXcbConnection::xEmbedSystemTrayAvailable()
+{
+ if (!QGuiApplicationPrivate::platformIntegration())
+ return false;
+ QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection();
+ return connection->systemTrayTracker();
+}
+
+bool QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel()
+{
+ if (!QGuiApplicationPrivate::platformIntegration())
+ return false;
+ QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection();
+ return connection->systemTrayTracker() && connection->systemTrayTracker()->visualHasAlphaChannel();
+}
+
bool QXcbConnection::event(QEvent *e)
{
if (e->type() == QEvent::User + 1) {
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index de454b5eae..4c014bc6e2 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -464,7 +464,9 @@ public:
QXcbNativeInterface *nativeInterface() const { return m_nativeInterface; }
- QXcbSystemTrayTracker *systemTrayTracker();
+ QXcbSystemTrayTracker *systemTrayTracker() const;
+ static bool xEmbedSystemTrayAvailable();
+ static bool xEmbedSystemTrayVisualHasAlphaChannel();
#ifdef XCB_USE_XINPUT2
void handleEnterEvent(const xcb_enter_notify_event_t *);
@@ -475,6 +477,7 @@ public:
bool canGrab() const { return m_canGrabServer; }
QXcbGlIntegration *glIntegration() const { return m_glIntegration; }
+
protected:
bool event(QEvent *e) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
index bfba7f2b6a..75ffaa37bb 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.cpp
@@ -47,6 +47,7 @@
#include <QtGui/qscreen.h>
#include <QtPlatformHeaders/qxcbwindowfunctions.h>
+#include <QtPlatformHeaders/qxcbintegrationfunctions.h>
#ifndef QT_NO_DBUS
#include "QtPlatformSupport/private/qdbusmenuconnection_p.h"
@@ -76,7 +77,8 @@ static int resourceType(const QByteArray &key)
QByteArrayLiteral("gettimestamp"), QByteArrayLiteral("x11screen"),
QByteArrayLiteral("rootwindow"),
QByteArrayLiteral("subpixeltype"), QByteArrayLiteral("antialiasingEnabled"),
- QByteArrayLiteral("nofonthinting")
+ QByteArrayLiteral("nofonthinting"),
+ QByteArrayLiteral("atspibus")
};
const QByteArray *end = names + sizeof(names) / sizeof(names[0]);
const QByteArray *result = std::find(names, end, key);
@@ -85,8 +87,7 @@ static int resourceType(const QByteArray &key)
QXcbNativeInterface::QXcbNativeInterface() :
m_genericEventFilterType(QByteArrayLiteral("xcb_generic_event_t")),
- m_sysTraySelectionAtom(XCB_ATOM_NONE),
- m_systrayVisualId(XCB_NONE)
+ m_sysTraySelectionAtom(XCB_ATOM_NONE)
{
}
@@ -117,22 +118,12 @@ bool QXcbNativeInterface::systemTrayAvailable(const QScreen *screen) const
bool QXcbNativeInterface::requestSystemTrayWindowDock(const QWindow *window)
{
- const QPlatformWindow *platformWindow = window->handle();
- if (!platformWindow)
- return false;
- QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen());
- if (!trayTracker)
- return false;
- trayTracker->requestSystemTrayWindowDock(static_cast<const QXcbWindow *>(platformWindow)->xcb_window());
- return true;
+ return QXcbWindow::requestSystemTrayWindowDockStatic(window);
}
QRect QXcbNativeInterface::systemTrayWindowGlobalGeometry(const QWindow *window)
{
- if (const QPlatformWindow *platformWindow = window->handle())
- if (const QXcbSystemTrayTracker *trayTracker = systemTrayTracker(window->screen()))
- return trayTracker->systemTrayWindowGlobalGeometry(static_cast<const QXcbWindow *>(platformWindow)->xcb_window());
- return QRect();
+ return QXcbWindow::systemTrayWindowGlobalGeometryStatic(window);
}
xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const QXcbScreen *screen)
@@ -163,54 +154,14 @@ xcb_window_t QXcbNativeInterface::locateSystemTray(xcb_connection_t *conn, const
return selection_window;
}
-bool QXcbNativeInterface::systrayVisualHasAlphaChannel() {
- const QXcbScreen *screen = static_cast<QXcbScreen *>(QGuiApplication::primaryScreen()->handle());
-
- if (m_systrayVisualId == XCB_NONE) {
- xcb_connection_t *xcb_conn = screen->xcb_connection();
- xcb_atom_t tray_atom = screen->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL);
-
- xcb_window_t systray_window = locateSystemTray(xcb_conn, screen);
- if (systray_window == XCB_WINDOW_NONE)
- return false;
-
- // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom
- xcb_get_property_cookie_t systray_atom_cookie;
- xcb_get_property_reply_t *systray_atom_reply;
-
- systray_atom_cookie = xcb_get_property_unchecked(xcb_conn, false, systray_window,
- tray_atom, XCB_ATOM_VISUALID, 0, 1);
- systray_atom_reply = xcb_get_property_reply(xcb_conn, systray_atom_cookie, 0);
-
- if (!systray_atom_reply)
- return false;
-
- if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) {
- xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply);
- m_systrayVisualId = vids[0];
- }
-
- free(systray_atom_reply);
- }
-
- if (m_systrayVisualId != XCB_NONE) {
- quint8 depth = screen->depthOfVisual(m_systrayVisualId);
- return depth == 32;
- } else {
- return false;
- }
+bool QXcbNativeInterface::systrayVisualHasAlphaChannel()
+{
+ return QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel();
}
-void QXcbNativeInterface::setParentRelativeBackPixmap(const QWindow *qwindow)
+void QXcbNativeInterface::setParentRelativeBackPixmap(QWindow *window)
{
- if (const QPlatformWindow *platformWindow = qwindow->handle()) {
- const QXcbWindow *qxwindow = static_cast<const QXcbWindow *>(platformWindow);
- xcb_connection_t *xcb_conn = qxwindow->xcb_connection();
-
- const quint32 mask = XCB_CW_BACK_PIXMAP;
- const quint32 values[] = { XCB_BACK_PIXMAP_PARENT_RELATIVE };
- Q_XCB_CALL(xcb_change_window_attributes(xcb_conn, qxwindow->xcb_window(), mask, values));
- }
+ QXcbWindow::setParentRelativeBackPixmapStatic(window);
}
void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resourceString)
@@ -233,6 +184,9 @@ void *QXcbNativeInterface::nativeResourceForIntegration(const QByteArray &resour
case Display:
result = display();
break;
+ case AtspiBus:
+ result = atspiBus();
+ break;
case Connection:
result = connection();
break;
@@ -389,9 +343,24 @@ QFunctionPointer QXcbNativeInterface::platformFunction(const QByteArray &functio
return func;
//case sensitive
- if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier()) {
- return QFunctionPointer(QXcbWindow::setWmWindowTypeStatic);
- }
+ if (function == QXcbWindowFunctions::setWmWindowTypeIdentifier())
+ return QFunctionPointer(QXcbWindowFunctions::SetWmWindowType(QXcbWindow::setWmWindowTypeStatic));
+
+ if (function == QXcbWindowFunctions::setWmWindowIconTextIdentifier())
+ return QFunctionPointer(QXcbWindowFunctions::SetWmWindowIconText(QXcbWindow::setWindowIconTextStatic));
+
+ if (function == QXcbWindowFunctions::setParentRelativeBackPixmapIdentifier())
+ return QFunctionPointer(QXcbWindowFunctions::SetParentRelativeBackPixmap(QXcbWindow::setParentRelativeBackPixmapStatic));
+
+ if (function == QXcbWindowFunctions::requestSystemTrayWindowDockIdentifier())
+ return QFunctionPointer(QXcbWindowFunctions::RequestSystemTrayWindowDock(QXcbWindow::requestSystemTrayWindowDockStatic));
+
+ if (function == QXcbWindowFunctions::systemTrayWindowGlobalGeometryIdentifier())
+ return QFunctionPointer(QXcbWindowFunctions::SystemTrayWindowGlobalGeometry(QXcbWindow::systemTrayWindowGlobalGeometryStatic));
+
+ if (function == QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannelIdentifier())
+ return QFunctionPointer(QXcbIntegrationFunctions::XEmbedSystemTrayVisualHasAlphaChannel(QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel));
+
return Q_NULLPTR;
}
@@ -463,6 +432,27 @@ void *QXcbNativeInterface::connection()
return integration->defaultConnection()->xcb_connection();
}
+void *QXcbNativeInterface::atspiBus()
+{
+ QXcbIntegration *integration = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QXcbConnection *defaultConnection = integration->defaultConnection();
+ if (defaultConnection) {
+ xcb_atom_t atspiBusAtom = defaultConnection->internAtom("AT_SPI_BUS");
+ xcb_get_property_cookie_t cookie = Q_XCB_CALL(xcb_get_property(defaultConnection->xcb_connection(), false,
+ defaultConnection->rootWindow(),
+ atspiBusAtom,
+ XCB_ATOM_STRING, 0, 128));
+ xcb_get_property_reply_t *reply = Q_XCB_CALL(xcb_get_property_reply(defaultConnection->xcb_connection(), cookie, 0));
+ Q_ASSERT(!reply->bytes_after);
+ char *data = (char *)xcb_get_property_value(reply);
+ int length = xcb_get_property_value_length(reply);
+ QByteArray *busAddress = new QByteArray(data, length);
+ free(reply);
+ return busAddress;
+ }
+ return 0;
+}
+
void QXcbNativeInterface::setAppTime(QScreen* screen, xcb_timestamp_t time)
{
if (screen) {
diff --git a/src/plugins/platforms/xcb/qxcbnativeinterface.h b/src/plugins/platforms/xcb/qxcbnativeinterface.h
index 721c6f4b1d..f88b710864 100644
--- a/src/plugins/platforms/xcb/qxcbnativeinterface.h
+++ b/src/plugins/platforms/xcb/qxcbnativeinterface.h
@@ -67,7 +67,8 @@ public:
RootWindow,
ScreenSubpixelType,
ScreenAntialiasingEnabled,
- NoFontHinting
+ NoFontHinting,
+ AtspiBus
};
QXcbNativeInterface();
@@ -98,6 +99,7 @@ public:
void *x11Screen();
void *rootWindow();
void *display();
+ void *atspiBus();
void *connection();
static void setStartupId(const char *);
static void setAppTime(QScreen *screen, xcb_timestamp_t time);
@@ -105,7 +107,7 @@ public:
Q_INVOKABLE void beep();
Q_INVOKABLE bool systemTrayAvailable(const QScreen *screen) const;
- Q_INVOKABLE void setParentRelativeBackPixmap(const QWindow *window);
+ Q_INVOKABLE void setParentRelativeBackPixmap(QWindow *window);
Q_INVOKABLE bool systrayVisualHasAlphaChannel();
Q_INVOKABLE bool requestSystemTrayWindowDock(const QWindow *window);
Q_INVOKABLE QRect systemTrayWindowGlobalGeometry(const QWindow *window);
@@ -121,7 +123,6 @@ private:
const QByteArray m_genericEventFilterType;
xcb_atom_t m_sysTraySelectionAtom;
- xcb_visualid_t m_systrayVisualId;
static QXcbScreen *qPlatformScreenForWindow(QWindow *window);
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
index a4fdd70b79..1f217e8de7 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.cpp
@@ -63,14 +63,14 @@ QXcbSystemTrayTracker *QXcbSystemTrayTracker::create(QXcbConnection *connection)
const xcb_atom_t selection = connection->internAtom(netSysTray.constData());
if (!selection)
return 0;
- return new QXcbSystemTrayTracker(connection, trayAtom, selection, connection);
+
+ return new QXcbSystemTrayTracker(connection, trayAtom, selection);
}
QXcbSystemTrayTracker::QXcbSystemTrayTracker(QXcbConnection *connection,
xcb_atom_t trayAtom,
- xcb_atom_t selection,
- QObject *parent)
- : QObject(parent)
+ xcb_atom_t selection)
+ : QObject(connection)
, m_selection(selection)
, m_trayAtom(trayAtom)
, m_connection(connection)
@@ -125,6 +125,7 @@ xcb_window_t QXcbSystemTrayTracker::trayWindow()
// does not work for the QWindow parented on the tray.
QRect QXcbSystemTrayTracker::systemTrayWindowGlobalGeometry(xcb_window_t window) const
{
+
xcb_connection_t *conn = m_connection->xcb_connection();
xcb_get_geometry_reply_t *geomReply =
xcb_get_geometry_reply(conn, xcb_get_geometry(conn, window), 0);
@@ -161,9 +162,43 @@ void QXcbSystemTrayTracker::handleDestroyNotifyEvent(const xcb_destroy_notify_ev
{
if (event->window == m_trayWindow) {
m_connection->removeWindowEventListener(m_trayWindow);
- m_trayWindow = 0;
+ m_trayWindow = XCB_WINDOW_NONE;
emitSystemTrayWindowChanged();
}
}
+bool QXcbSystemTrayTracker::visualHasAlphaChannel()
+{
+ if (m_trayWindow == XCB_WINDOW_NONE)
+ return false;
+
+ xcb_atom_t tray_atom = m_connection->atom(QXcbAtom::_NET_SYSTEM_TRAY_VISUAL);
+
+ // Get the xcb property for the _NET_SYSTEM_TRAY_VISUAL atom
+ xcb_get_property_cookie_t systray_atom_cookie;
+ xcb_get_property_reply_t *systray_atom_reply;
+
+ systray_atom_cookie = xcb_get_property_unchecked(m_connection->xcb_connection(), false, m_trayWindow,
+ tray_atom, XCB_ATOM_VISUALID, 0, 1);
+ systray_atom_reply = xcb_get_property_reply(m_connection->xcb_connection(), systray_atom_cookie, 0);
+
+ if (!systray_atom_reply)
+ return false;
+
+ xcb_visualid_t systrayVisualId = XCB_NONE;
+ if (systray_atom_reply->value_len > 0 && xcb_get_property_value_length(systray_atom_reply) > 0) {
+ xcb_visualid_t * vids = (uint32_t *)xcb_get_property_value(systray_atom_reply);
+ systrayVisualId = vids[0];
+ }
+
+ free(systray_atom_reply);
+
+ if (systrayVisualId != XCB_NONE) {
+ quint8 depth = m_connection->primaryScreen()->depthOfVisual(systrayVisualId);
+ return depth == 32;
+ }
+
+ return false;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
index 9c20f1729a..b619afb9c4 100644
--- a/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
+++ b/src/plugins/platforms/xcb/qxcbsystemtraytracker.h
@@ -57,14 +57,14 @@ public:
void handleDestroyNotifyEvent(const xcb_destroy_notify_event_t *) Q_DECL_OVERRIDE;
+ bool visualHasAlphaChannel();
signals:
void systemTrayWindowChanged(QScreen *screen);
private:
explicit QXcbSystemTrayTracker(QXcbConnection *connection,
xcb_atom_t trayAtom,
- xcb_atom_t selection,
- QObject *parent = 0);
+ xcb_atom_t selection);
static xcb_window_t locateTrayWindow(const QXcbConnection *connection, xcb_atom_t selection);
void emitSystemTrayWindowChanged();
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 78ccf8a3e9..eabebffdab 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -46,6 +46,7 @@
#include "qxcbwmsupport.h"
#include "qxcbimage.h"
#include "qxcbnativeinterface.h"
+#include "qxcbsystemtraytracker.h"
#include <qpa/qplatformintegration.h>
@@ -1409,10 +1410,22 @@ void QXcbWindow::setWindowTitle(const QString &title)
xcb_flush(xcb_connection());
}
+void QXcbWindow::setWindowIconText(const QString &title)
+{
+ const QByteArray ba = title.toUtf8();
+ Q_XCB_CALL(xcb_change_property(xcb_connection(),
+ XCB_PROP_MODE_REPLACE,
+ m_window,
+ atom(QXcbAtom::_NET_WM_ICON_NAME),
+ atom(QXcbAtom::UTF8_STRING),
+ 8,
+ ba.length(),
+ ba.constData()));
+}
+
void QXcbWindow::setWindowIcon(const QIcon &icon)
{
QVector<quint32> icon_data;
-
if (!icon.isNull()) {
QList<QSize> availableSizes = icon.availableSizes();
if (availableSizes.isEmpty()) {
@@ -1577,6 +1590,12 @@ void QXcbWindow::setWmWindowTypeStatic(QWindow *window, QXcbWindowFunctions::WmW
window->setProperty(wm_window_type_property_id, QVariant::fromValue(static_cast<int>(windowTypes)));
}
+void QXcbWindow::setWindowIconTextStatic(QWindow *window, const QString &text)
+{
+ if (window->handle())
+ static_cast<QXcbWindow *>(window->handle())->setWindowIconText(text);
+}
+
QXcbWindowFunctions::WmWindowTypes QXcbWindow::wmWindowTypes() const
{
QXcbWindowFunctions::WmWindowTypes result(0);
@@ -1693,6 +1712,48 @@ void QXcbWindow::setWmWindowType(QXcbWindowFunctions::WmWindowTypes types)
xcb_flush(xcb_connection());
}
+void QXcbWindow::setParentRelativeBackPixmapStatic(QWindow *window)
+{
+ if (window->handle())
+ static_cast<QXcbWindow *>(window->handle())->setParentRelativeBackPixmap();
+}
+
+void QXcbWindow::setParentRelativeBackPixmap()
+{
+ const quint32 mask = XCB_CW_BACK_PIXMAP;
+ const quint32 values[] = { XCB_BACK_PIXMAP_PARENT_RELATIVE };
+ Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
+}
+
+bool QXcbWindow::requestSystemTrayWindowDockStatic(const QWindow *window)
+{
+ if (window->handle())
+ return static_cast<QXcbWindow *>(window->handle())->requestSystemTrayWindowDock();
+ return false;
+}
+
+bool QXcbWindow::requestSystemTrayWindowDock() const
+{
+ if (!connection()->systemTrayTracker())
+ return false;
+ connection()->systemTrayTracker()->requestSystemTrayWindowDock(m_window);
+ return true;
+}
+
+QRect QXcbWindow::systemTrayWindowGlobalGeometryStatic(const QWindow *window)
+{
+ if (window->handle())
+ return static_cast<QXcbWindow *>(window->handle())->systemTrayWindowGlobalGeometry();
+ return QRect();
+}
+
+QRect QXcbWindow::systemTrayWindowGlobalGeometry() const
+{
+ if (!connection()->systemTrayTracker())
+ return QRect();
+ return connection()->systemTrayTracker()->systemTrayWindowGlobalGeometry(m_window);
+}
+
class ExposeCompressor
{
public:
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 8f78be573c..cd3c091973 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -86,6 +86,7 @@ public:
QPoint mapFromGlobal(const QPoint &pos) const Q_DECL_OVERRIDE;
void setWindowTitle(const QString &title) Q_DECL_OVERRIDE;
+ void setWindowIconText(const QString &title);
void setWindowIcon(const QIcon &icon) Q_DECL_OVERRIDE;
void raise() Q_DECL_OVERRIDE;
void lower() Q_DECL_OVERRIDE;
@@ -142,6 +143,17 @@ public:
QXcbWindowFunctions::WmWindowTypes wmWindowTypes() const;
void setWmWindowType(QXcbWindowFunctions::WmWindowTypes types);
+ static void setWindowIconTextStatic(QWindow *window, const QString &text);
+
+ static void setParentRelativeBackPixmapStatic(QWindow *window);
+ void setParentRelativeBackPixmap();
+
+ static bool requestSystemTrayWindowDockStatic(const QWindow *window);
+ bool requestSystemTrayWindowDock() const;
+
+ static QRect systemTrayWindowGlobalGeometryStatic(const QWindow *window);
+ QRect systemTrayWindowGlobalGeometry() const;
+
bool needsSync() const;
void postSyncWindowRequest();
diff --git a/src/src.pro b/src/src.pro
index 3dd9f8c9ce..35270cebc5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -107,7 +107,7 @@ src_platformsupport.depends = src_corelib src_gui src_platformheaders
src_widgets.subdir = $$PWD/widgets
src_widgets.target = sub-widgets
-src_widgets.depends = src_corelib src_gui src_tools_uic
+src_widgets.depends = src_corelib src_gui src_tools_uic src_platformheaders
src_opengl.subdir = $$PWD/opengl
src_opengl.target = sub-opengl
diff --git a/src/testlib/qtestblacklist.cpp b/src/testlib/qtestblacklist.cpp
index 1cf2ee09e3..bf795fcd68 100644
--- a/src/testlib/qtestblacklist.cpp
+++ b/src/testlib/qtestblacklist.cpp
@@ -36,6 +36,9 @@
#include <QtTest/qtestcase.h>
#include <QtCore/qbytearray.h>
#include <QtCore/qfile.h>
+#include <QtCore/qset.h>
+#include <QtCore/qcoreapplication.h>
+#include <QtCore/qvariant.h>
#include <set>
@@ -59,67 +62,71 @@ QT_BEGIN_NAMESPACE
The known keys are listed below:
*/
-// this table can be extended with new keywords as required
-const char *matchedConditions[] =
+static QSet<QByteArray> keywords()
{
- "*",
+ // this list can be extended with new keywords as required
+ QSet<QByteArray> set = QSet<QByteArray>()
+ << "*"
#ifdef Q_OS_LINUX
- "linux",
+ << "linux"
#endif
#ifdef Q_OS_OSX
- "osx",
+ << "osx"
#endif
#ifdef Q_OS_WIN
- "windows",
+ << "windows"
#endif
#ifdef Q_OS_IOS
- "ios",
+ << "ios"
#endif
#ifdef Q_OS_ANDROID
- "android",
+ << "android"
#endif
#ifdef Q_OS_QNX
- "qnx",
+ << "qnx"
#endif
#ifdef Q_OS_WINRT
- "winrt",
+ << "winrt"
#endif
#ifdef Q_OS_WINCE
- "wince",
+ << "wince"
#endif
#if QT_POINTER_SIZE == 8
- "64bit",
+ << "64bit"
#else
- "32bit",
+ << "32bit"
#endif
#ifdef Q_CC_GNU
- "gcc",
+ << "gcc"
#endif
#ifdef Q_CC_CLANG
- "clang",
+ << "clang"
#endif
#ifdef Q_CC_MSVC
- "msvc",
+ << "msvc"
#endif
#ifdef Q_AUTOTEST_EXPORT
- "developer-build",
+ << "developer-build"
#endif
- 0
-};
+ ;
+ QCoreApplication *app = QCoreApplication::instance();
+ if (app) {
+ const QVariant platformName = app->property("platformName");
+ if (platformName.isValid())
+ set << platformName.toByteArray();
+ }
+
+ return set;
+}
static bool checkCondition(const QByteArray &condition)
{
+ static QSet<QByteArray> matchedConditions = keywords();
QList<QByteArray> conds = condition.split(' ');
- std::set<QByteArray> matches;
- const char **m = matchedConditions;
- while (*m) {
- matches.insert(*m);
- ++m;
- }
for (int i = 0; i < conds.size(); ++i) {
QByteArray c = conds.at(i);
@@ -127,7 +134,7 @@ static bool checkCondition(const QByteArray &condition)
if (result)
c = c.mid(1);
- result ^= (matches.find(c) != matches.end());
+ result ^= matchedConditions.contains(c);
if (!result)
return false;
}
diff --git a/src/tools/qdoc/config.cpp b/src/tools/qdoc/config.cpp
index 606bb1c619..13add73322 100644
--- a/src/tools/qdoc/config.cpp
+++ b/src/tools/qdoc/config.cpp
@@ -912,8 +912,10 @@ QStringList Config::loadMaster(const QString& fileName)
*/
void Config::load(Location location, const QString& fileName)
{
- pushWorkingDir(QFileInfo(fileName).path());
- QDir::setCurrent(QFileInfo(fileName).path());
+ QFileInfo fileInfo(fileName);
+ QString path = fileInfo.canonicalPath();
+ pushWorkingDir(path);
+ QDir::setCurrent(path);
QRegExp keySyntax(QLatin1String("\\w+(?:\\.\\w+)*"));
#define SKIP_CHAR() \
@@ -935,7 +937,7 @@ void Config::load(Location location, const QString& fileName)
if (location.depth() > 16)
location.fatal(tr("Too many nested includes"));
- QFile fin(fileName);
+ QFile fin(fileInfo.fileName());
if (!fin.open(QFile::ReadOnly | QFile::Text)) {
if (!Config::installDir.isEmpty()) {
int prefix = location.filePath().length() - location.fileName().length();
@@ -1030,7 +1032,7 @@ void Config::load(Location location, const QString& fileName)
/*
Here is the recursive call.
*/
- load(location, QFileInfo(QFileInfo(fileName).dir(), includeFile).filePath());
+ load(location, QFileInfo(QDir(path), includeFile).filePath());
}
else {
/*
diff --git a/src/tools/qdoc/helpprojectwriter.cpp b/src/tools/qdoc/helpprojectwriter.cpp
index 90b1d9cfe3..2ae952a962 100644
--- a/src/tools/qdoc/helpprojectwriter.cpp
+++ b/src/tools/qdoc/helpprojectwriter.cpp
@@ -107,13 +107,13 @@ void HelpProjectWriter::reset(const Config &config,
subproject.sortPages = config.getBool(subprefix + "sortPages");
subproject.type = config.getString(subprefix + "type");
readSelectors(subproject, config.getStringList(subprefix + "selectors"));
- project.subprojects[name] = subproject;
+ project.subprojects.append(subproject);
}
if (project.subprojects.isEmpty()) {
SubProject subproject;
readSelectors(subproject, config.getStringList(prefix + "selectors"));
- project.subprojects.insert(QString(), subproject);
+ project.subprojects.insert(0, subproject);
}
projects.append(project);
@@ -260,16 +260,16 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
// Only add nodes to the set for each subproject if they match a selector.
// Those that match will be listed in the table of contents.
- foreach (const QString &name, project.subprojects.keys()) {
- SubProject subproject = project.subprojects[name];
+ for (int i = 0; i < project.subprojects.length(); i++) {
+ SubProject subproject = project.subprojects[i];
// No selectors: accept all nodes.
if (subproject.selectors.isEmpty()) {
- project.subprojects[name].nodes[objName] = node;
+ project.subprojects[i].nodes[objName] = node;
}
else if (subproject.selectors.contains(node->type())) {
// Accept only the node types in the selectors hash.
if (node->type() != Node::Document)
- project.subprojects[name].nodes[objName] = node;
+ project.subprojects[i].nodes[objName] = node;
else {
// Accept only fake nodes with subtypes contained in the selector's
// mask.
@@ -278,7 +278,7 @@ bool HelpProjectWriter::generateSection(HelpProject &project,
docNode->subType() != Node::ExternalPage &&
!docNode->fullTitle().isEmpty()) {
- project.subprojects[name].nodes[objName] = node;
+ project.subprojects[i].nodes[objName] = node;
}
}
}
@@ -713,8 +713,8 @@ void HelpProjectWriter::generateProject(HelpProject &project)
generateSections(project, writer, rootNode);
- foreach (const QString &name, project.subprojects.keys()) {
- SubProject subproject = project.subprojects[name];
+ for (int i = 0; i < project.subprojects.length(); i++) {
+ SubProject subproject = project.subprojects[i];
if (subproject.type == QLatin1String("manual")) {
@@ -769,13 +769,12 @@ void HelpProjectWriter::generateProject(HelpProject &project)
} else {
- if (!name.isEmpty()) {
- writer.writeStartElement("section");
- QString indexPath = gen_->fullDocumentLocation(qdb_->findNodeForTarget(subproject.indexTitle, 0),
+ writer.writeStartElement("section");
+ QString indexPath = gen_->fullDocumentLocation(qdb_->findNodeForTarget(subproject.indexTitle, 0),
false);
- writer.writeAttribute("ref", indexPath);
- writer.writeAttribute("title", subproject.title);
- }
+ writer.writeAttribute("ref", indexPath);
+ writer.writeAttribute("title", subproject.title);
+
if (subproject.sortPages) {
QStringList titles = subproject.nodes.keys();
titles.sort();
@@ -815,8 +814,7 @@ void HelpProjectWriter::generateProject(HelpProject &project)
}
}
- if (!name.isEmpty())
- writer.writeEndElement(); // section
+ writer.writeEndElement(); // section
}
}
diff --git a/src/tools/qdoc/helpprojectwriter.h b/src/tools/qdoc/helpprojectwriter.h
index efc2596296..8f21238c2a 100644
--- a/src/tools/qdoc/helpprojectwriter.h
+++ b/src/tools/qdoc/helpprojectwriter.h
@@ -70,7 +70,7 @@ struct HelpProject
QSet<QString> filterAttributes;
QHash<QString, QSet<QString> > customFilters;
QSet<QString> excluded;
- QMap<QString, SubProject> subprojects;
+ QList<SubProject> subprojects;
QHash<const Node *, QSet<Node::Status> > memberStatus;
bool includeIndexNodes;
};
diff --git a/src/tools/qdoc/main.cpp b/src/tools/qdoc/main.cpp
index 74d706efe1..4a99ec39de 100644
--- a/src/tools/qdoc/main.cpp
+++ b/src/tools/qdoc/main.cpp
@@ -227,6 +227,8 @@ static void processQdocconfFile(const QString &fileName)
config.setStringList(CONFIG_AUTOLINKERRORS, QStringList(autolinkErrors ? "true" : "false"));
config.setStringList(CONFIG_OBSOLETELINKS, QStringList(obsoleteLinks ? "true" : "false"));
+ prevCurrentDir = QDir::currentPath();
+
/*
With the default configuration values in place, load
the qdoc configuration file. Note that the configuration
@@ -236,7 +238,6 @@ static void processQdocconfFile(const QString &fileName)
in the file being processed, mainly for error reporting
purposes.
*/
- currentDir = QFileInfo(fileName).path();
Location::initialize(config);
config.load(fileName);
QString project = config.getString(CONFIG_PROJECT);
@@ -248,7 +249,6 @@ static void processQdocconfFile(const QString &fileName)
config.setStringList(CONFIG_DEFINES,defs);
Location::terminate();
- prevCurrentDir = QDir::currentPath();
currentDir = QFileInfo(fileName).path();
if (!currentDir.isEmpty())
QDir::setCurrent(currentDir);
diff --git a/src/widgets/accessible/qaccessiblewidgets.cpp b/src/widgets/accessible/qaccessiblewidgets.cpp
index 7080dd6f8d..c598a5b4cb 100644
--- a/src/widgets/accessible/qaccessiblewidgets.cpp
+++ b/src/widgets/accessible/qaccessiblewidgets.cpp
@@ -667,12 +667,25 @@ QRect QAccessibleTextWidget::characterRect(int offset) const
if (line.isValid()) {
qreal x = line.cursorToX(relativeOffset);
- QFontMetrics fm(textCursor().charFormat().font());
+
+ QTextCharFormat format;
+ QTextBlock::iterator iter = block.begin();
+ if (iter.atEnd())
+ format = block.charFormat();
+ else {
+ while (!iter.atEnd() && !iter.fragment().contains(offset))
+ ++iter;
+ if (iter.atEnd()) // newline should have same format as preceding character
+ --iter;
+ format = iter.fragment().charFormat();
+ }
+
+ QFontMetrics fm(format.font());
const QString ch = text(offset, offset + 1);
if (!ch.isEmpty()) {
int w = fm.width(ch);
int h = fm.height();
- r = QRect(layoutPosition.x() + x, layoutPosition.y() + line.y(),
+ r = QRect(layoutPosition.x() + x, layoutPosition.y() + line.y() + line.ascent() + fm.descent() - h,
w, h);
r.moveTo(viewport()->mapToGlobal(r.topLeft()));
}
@@ -776,7 +789,45 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end
QFont::Style style = charFormat.font().style();
attrs["font-style"] = QString::fromLatin1((style == QFont::StyleItalic) ? "italic" : ((style == QFont::StyleOblique) ? "oblique": "normal"));
- attrs["text-underline-style"] = QString::fromLatin1(charFormat.font().underline() ? "solid" : "none");
+ QTextCharFormat::UnderlineStyle underlineStyle = charFormat.underlineStyle();
+ if (underlineStyle == QTextCharFormat::NoUnderline && charFormat.font().underline()) // underline could still be set in the default font
+ underlineStyle = QTextCharFormat::SingleUnderline;
+ QString underlineStyleValue;
+ switch (underlineStyle) {
+ case QTextCharFormat::NoUnderline:
+ break;
+ case QTextCharFormat::SingleUnderline:
+ underlineStyleValue = QStringLiteral("solid");
+ break;
+ case QTextCharFormat::DashUnderline:
+ underlineStyleValue = QStringLiteral("dash");
+ break;
+ case QTextCharFormat::DotLine:
+ underlineStyleValue = QStringLiteral("dash");
+ break;
+ case QTextCharFormat::DashDotLine:
+ underlineStyleValue = QStringLiteral("dot-dash");
+ break;
+ case QTextCharFormat::DashDotDotLine:
+ underlineStyleValue = QStringLiteral("dot-dot-dash");
+ break;
+ case QTextCharFormat::WaveUnderline:
+ underlineStyleValue = QStringLiteral("wave");
+ break;
+ case QTextCharFormat::SpellCheckUnderline:
+ underlineStyleValue = QStringLiteral("wave"); // this is not correct, but provides good approximation at least
+ break;
+ default:
+ qWarning() << "Unknown QTextCharFormat::​UnderlineStyle value " << underlineStyle << " could not be translated to IAccessible2 value";
+ break;
+ }
+ if (!underlineStyleValue.isNull()) {
+ attrs["text-underline-style"] = underlineStyleValue;
+ attrs["text-underline-type"] = QStringLiteral("single"); // if underlineStyleValue is set, there is an underline, and Qt does not support other than single ones
+ } // else both are "none" which is the default - no need to set them
+
+ if (block.textDirection() == Qt::RightToLeft)
+ attrs["writing-mode"] = QStringLiteral("rl");
QTextCharFormat::VerticalAlignment alignment = charFormat.verticalAlignment();
attrs["text-position"] = QString::fromLatin1((alignment == QTextCharFormat::AlignSubScript) ? "sub" : ((alignment == QTextCharFormat::AlignSuperScript) ? "super" : "baseline" ));
diff --git a/src/widgets/dialogs/dialogs.pri b/src/widgets/dialogs/dialogs.pri
index 53d1985fb5..206b394ed6 100644
--- a/src/widgets/dialogs/dialogs.pri
+++ b/src/widgets/dialogs/dialogs.pri
@@ -2,7 +2,6 @@
HEADERS += \
dialogs/qcolordialog.h \
- dialogs/qcolordialog_p.h \
dialogs/qfscompleter_p.h \
dialogs/qdialog.h \
dialogs/qdialog_p.h \
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index 5f3161f39f..914ee8ec9c 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -31,7 +31,7 @@
**
****************************************************************************/
-#include "qcolordialog_p.h"
+#include "qcolordialog.h"
#ifndef QT_NO_COLORDIALOG
@@ -49,6 +49,7 @@
#include "qpixmap.h"
#include "qpushbutton.h"
#include "qsettings.h"
+#include "qsharedpointer.h"
#include "qstyle.h"
#include "qstyleoption.h"
#include "qvalidator.h"
@@ -58,13 +59,132 @@
#include "qscreen.h"
#include "qcursor.h"
#include "qtimer.h"
+#include "qwindow.h"
+
+#include "private/qdialog_p.h"
#include <algorithm>
QT_BEGIN_NAMESPACE
+namespace {
+class QColorLuminancePicker;
+class QColorPicker;
+class QColorShower;
+class QWellArray;
+class QColorPickingEventFilter;
+} // unnamed namespace
+
+class QColorDialogPrivate : public QDialogPrivate
+{
+ Q_DECLARE_PUBLIC(QColorDialog)
+
+public:
+ enum SetColorMode {
+ ShowColor = 0x1,
+ SelectColor = 0x2,
+ SetColorAll = ShowColor | SelectColor
+ };
+
+ QColorDialogPrivate() : options(new QColorDialogOptions)
+#ifdef Q_OS_WIN32
+ , updateTimer(0)
+#endif
+ {}
+
+ QPlatformColorDialogHelper *platformColorDialogHelper() const
+ { return static_cast<QPlatformColorDialogHelper *>(platformHelper()); }
+
+ void init(const QColor &initial);
+ void initWidgets();
+ QRgb currentColor() const;
+ QColor currentQColor() const;
+ void setCurrentColor(const QColor &color, SetColorMode setColorMode = SetColorAll);
+ void setCurrentRgbColor(QRgb rgb);
+ void setCurrentQColor(const QColor &color);
+ bool selectColor(const QColor &color);
+ QColor grabScreenColor(const QPoint &p);
+
+ int currentAlpha() const;
+ void setCurrentAlpha(int a);
+ void showAlpha(bool b);
+ bool isAlphaVisible() const;
+ void retranslateStrings();
+
+ void _q_addCustom();
+
+ void _q_newHsv(int h, int s, int v);
+ void _q_newColorTypedIn(QRgb rgb);
+ void _q_nextCustom(int, int);
+ void _q_newCustom(int, int);
+ void _q_newStandard(int, int);
+ void _q_pickScreenColor();
+ void _q_updateColorPicking();
+ void updateColorLabelText(const QPoint &);
+ void updateColorPicking(const QPoint &pos);
+ void releaseColorPicking();
+ bool handleColorPickingMouseMove(QMouseEvent *e);
+ bool handleColorPickingMouseButtonRelease(QMouseEvent *e);
+ bool handleColorPickingKeyPress(QKeyEvent *e);
+
+ bool canBeNativeDialog() const Q_DECL_OVERRIDE;
+
+ QWellArray *custom;
+ QWellArray *standard;
+
+ QDialogButtonBox *buttons;
+ QVBoxLayout *leftLay;
+ QColorPicker *cp;
+ QColorLuminancePicker *lp;
+ QColorShower *cs;
+ QLabel *lblBasicColors;
+ QLabel *lblCustomColors;
+ QLabel *lblScreenColorInfo;
+ QPushButton *ok;
+ QPushButton *cancel;
+ QPushButton *addCusBt;
+ QPushButton *screenColorPickerButton;
+ QColor selectedQColor;
+ int nextCust;
+ bool smallDisplay;
+ bool screenColorPicking;
+ QColorPickingEventFilter *colorPickingEventFilter;
+ QRgb beforeScreenColorPicking;
+ QSharedPointer<QColorDialogOptions> options;
+
+ QPointer<QObject> receiverToDisconnectOnClose;
+ QByteArray memberToDisconnectOnClose;
+#ifdef Q_OS_WIN32
+ QTimer *updateTimer;
+ QWindow dummyTransparentWindow;
+#endif
+
+#ifdef Q_DEAD_CODE_FROM_QT4_MAC
+ void openCocoaColorPanel(const QColor &initial,
+ QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options);
+ void closeCocoaColorPanel();
+ void releaseCocoaColorPanelDelegate();
+ void setCocoaPanelColor(const QColor &color);
+
+ inline void done(int result) { q_func()->done(result); }
+ inline QColorDialog *colorDialog() { return q_func(); }
+
+ void *delegate;
+
+ static bool sharedColorPanelAvailable;
+
+ void _q_macRunNativeAppModalPanel();
+ void mac_nativeDialogModalHelp();
+#endif
+private:
+ virtual void initHelper(QPlatformDialogHelper *h) Q_DECL_OVERRIDE;
+ virtual void helperPrepareShow(QPlatformDialogHelper *h) Q_DECL_OVERRIDE;
+};
+
//////////// QWellArray BEGIN
+namespace {
+
struct QWellArrayData;
class QWellArray : public QWidget
@@ -446,6 +566,8 @@ private:
QColorDialogPrivate *m_dp;
};
+} // unnamed namespace
+
/*!
Returns the number of custom colors supported by QColorDialog. All
color dialogs share the same custom colors.
@@ -506,6 +628,8 @@ static inline void rgb2hsv(QRgb rgb, int &h, int &s, int &v)
c.getHsv(&h, &s, &v);
}
+namespace {
+
class QColorWell : public QWellArray
{
public:
@@ -975,8 +1099,8 @@ private:
QColorDialog *colorDialog;
QGridLayout *gl;
- friend class QColorDialog;
- friend class QColorDialogPrivate;
+ friend class QT_PREPEND_NAMESPACE(QColorDialog);
+ friend class QT_PREPEND_NAMESPACE(QColorDialogPrivate);
};
class QColorShowLabel : public QFrame
@@ -1265,6 +1389,8 @@ QColorShower::QColorShower(QColorDialog *parent)
retranslateStrings();
}
+} // unnamed namespace
+
inline QRgb QColorDialogPrivate::currentColor() const { return cs->currentColor(); }
inline int QColorDialogPrivate::currentAlpha() const { return cs->currentAlpha(); }
inline void QColorDialogPrivate::setCurrentAlpha(int a) { cs->setCurrentAlpha(a); }
diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h
index 16339f56c4..43c7716ef6 100644
--- a/src/widgets/dialogs/qcolordialog.h
+++ b/src/widgets/dialogs/qcolordialog.h
@@ -113,7 +113,6 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int))
Q_PRIVATE_SLOT(d_func(), void _q_pickScreenColor())
Q_PRIVATE_SLOT(d_func(), void _q_updateColorPicking())
- friend class QColorShower;
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QColorDialog::ColorDialogOptions)
diff --git a/src/widgets/dialogs/qcolordialog_p.h b/src/widgets/dialogs/qcolordialog_p.h
deleted file mode 100644
index 1a881eae70..0000000000
--- a/src/widgets/dialogs/qcolordialog_p.h
+++ /dev/null
@@ -1,179 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2015 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
-**
-** This file is part of the QtWidgets module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL21$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see http://www.qt.io/terms-conditions. For further
-** information use the contact form at http://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 or version 3 as published by the Free
-** Software Foundation and appearing in the file LICENSE.LGPLv21 and
-** LICENSE.LGPLv3 included in the packaging of this file. Please review the
-** following information to ensure the GNU Lesser General Public License
-** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** As a special exception, The Qt Company gives you certain additional
-** rights. These rights are described in The Qt Company LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QCOLORDIALOG_P_H
-#define QCOLORDIALOG_P_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// to version without notice, or even be removed.
-//
-// We mean it.
-//
-//
-
-#include "private/qdialog_p.h"
-#include "qcolordialog.h"
-#include "qsharedpointer.h"
-#include "qwindow.h"
-
-#ifndef QT_NO_COLORDIALOG
-
-QT_BEGIN_NAMESPACE
-
-class QColorLuminancePicker;
-class QColorPicker;
-class QColorShower;
-class QDialogButtonBox;
-class QLabel;
-class QVBoxLayout;
-class QPushButton;
-class QWellArray;
-class QColorPickingEventFilter;
-class QTimer;
-
-class QColorDialogPrivate : public QDialogPrivate
-{
- Q_DECLARE_PUBLIC(QColorDialog)
-
-public:
- enum SetColorMode {
- ShowColor = 0x1,
- SelectColor = 0x2,
- SetColorAll = ShowColor | SelectColor
- };
-
- QColorDialogPrivate() : options(new QColorDialogOptions)
-#ifdef Q_OS_WIN32
- , updateTimer(0)
-#endif
- {}
-
- QPlatformColorDialogHelper *platformColorDialogHelper() const
- { return static_cast<QPlatformColorDialogHelper *>(platformHelper()); }
-
- void init(const QColor &initial);
- void initWidgets();
- QRgb currentColor() const;
- QColor currentQColor() const;
- void setCurrentColor(const QColor &color, SetColorMode setColorMode = SetColorAll);
- void setCurrentRgbColor(QRgb rgb);
- void setCurrentQColor(const QColor &color);
- bool selectColor(const QColor &color);
- QColor grabScreenColor(const QPoint &p);
-
- int currentAlpha() const;
- void setCurrentAlpha(int a);
- void showAlpha(bool b);
- bool isAlphaVisible() const;
- void retranslateStrings();
-
- void _q_addCustom();
-
- void _q_newHsv(int h, int s, int v);
- void _q_newColorTypedIn(QRgb rgb);
- void _q_nextCustom(int, int);
- void _q_newCustom(int, int);
- void _q_newStandard(int, int);
- void _q_pickScreenColor();
- void _q_updateColorPicking();
- void updateColorLabelText(const QPoint &);
- void updateColorPicking(const QPoint &pos);
- void releaseColorPicking();
- bool handleColorPickingMouseMove(QMouseEvent *e);
- bool handleColorPickingMouseButtonRelease(QMouseEvent *e);
- bool handleColorPickingKeyPress(QKeyEvent *e);
-
- bool canBeNativeDialog() const Q_DECL_OVERRIDE;
-
- QWellArray *custom;
- QWellArray *standard;
-
- QDialogButtonBox *buttons;
- QVBoxLayout *leftLay;
- QColorPicker *cp;
- QColorLuminancePicker *lp;
- QColorShower *cs;
- QLabel *lblBasicColors;
- QLabel *lblCustomColors;
- QLabel *lblScreenColorInfo;
- QPushButton *ok;
- QPushButton *cancel;
- QPushButton *addCusBt;
- QPushButton *screenColorPickerButton;
- QColor selectedQColor;
- int nextCust;
- bool smallDisplay;
- bool screenColorPicking;
- QColorPickingEventFilter *colorPickingEventFilter;
- QRgb beforeScreenColorPicking;
- QSharedPointer<QColorDialogOptions> options;
-
- QPointer<QObject> receiverToDisconnectOnClose;
- QByteArray memberToDisconnectOnClose;
-#ifdef Q_OS_WIN32
- QTimer *updateTimer;
- QWindow dummyTransparentWindow;
-#endif
-
-#ifdef Q_DEAD_CODE_FROM_QT4_MAC
- void openCocoaColorPanel(const QColor &initial,
- QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options);
- void closeCocoaColorPanel();
- void releaseCocoaColorPanelDelegate();
- void setCocoaPanelColor(const QColor &color);
-
- inline void done(int result) { q_func()->done(result); }
- inline QColorDialog *colorDialog() { return q_func(); }
-
- void *delegate;
-
- static bool sharedColorPanelAvailable;
-
- void _q_macRunNativeAppModalPanel();
- void mac_nativeDialogModalHelp();
-#endif
-private:
- virtual void initHelper(QPlatformDialogHelper *h) Q_DECL_OVERRIDE;
- virtual void helperPrepareShow(QPlatformDialogHelper *h) Q_DECL_OVERRIDE;
-};
-
-#endif // QT_NO_COLORDIALOG
-
-QT_END_NAMESPACE
-
-#endif // QCOLORDIALOG_P_H
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index e1053b4add..ad0142c5df 100644
--- a/src/widgets/kernel/qwidget.cpp
+++ b/src/widgets/kernel/qwidget.cpp
@@ -100,6 +100,7 @@
#include "qwindowcontainer_p.h"
+#include <QtPlatformHeaders/qxcbwindowfunctions.h>
// widget/widget data creation count
//#define QWIDGET_EXTRA_DEBUG
@@ -704,7 +705,7 @@ void QWidget::setAutoFillBackground(bool enabled)
close().
\row \li Top-level windows \li
- \l windowModified, \l windowTitle, \l windowIcon, \l windowIconText,
+ \l windowModified, \l windowTitle, \l windowIcon,
\l isActiveWindow, activateWindow(), \l minimized, showMinimized(),
\l maximized, showMaximized(), \l fullScreen, showFullScreen(),
showNormal().
@@ -5937,7 +5938,7 @@ void QWidget::unsetLocale()
window title, if set. This is done by the QPA plugin, so it is shown to the
user, but isn't part of the windowTitle string.
- \sa windowIcon, windowIconText, windowModified, windowFilePath
+ \sa windowIcon, windowModified, windowFilePath
*/
QString QWidget::windowTitle() const
{
@@ -6032,7 +6033,11 @@ void QWidgetPrivate::setWindowIconText_helper(const QString &title)
void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
{
- Q_UNUSED(iconText);
+ Q_Q(QWidget);
+ // ### The QWidget property is deprecated, but the XCB window function is not.
+ // It should remain available for the rare application that needs it.
+ if (QWindow *window = q->windowHandle())
+ QXcbWindowFunctions::setWmWindowIconText(window, iconText);
}
/*!
@@ -6042,6 +6047,9 @@ void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
new \a iconText as an argument.
\since 5.2
+ \obsolete
+
+ This signal is deprecated.
*/
void QWidget::setWindowIconText(const QString &iconText)
@@ -6092,7 +6100,7 @@ void QWidget::setWindowTitle(const QString &title)
has been set, windowIcon() returns the application icon
(QApplication::windowIcon()).
- \sa windowIconText, windowTitle
+ \sa windowTitle
*/
QIcon QWidget::windowIcon() const
{
@@ -6152,10 +6160,15 @@ void QWidgetPrivate::setWindowIcon_sys()
/*!
\property QWidget::windowIconText
- \brief the widget's icon text
+ \brief the text to be displayed on the icon of a minimized window
This property only makes sense for windows. If no icon
- text has been set, this functions returns an empty string.
+ text has been set, this accessor returns an empty string.
+ It is only implemented on the X11 platform, and only certain
+ window managers use this window property.
+
+ \obsolete
+ This property is deprecated.
\sa windowIcon, windowTitle
*/
@@ -12809,6 +12822,65 @@ void QWidgetPrivate::setWidgetParentHelper(QObject *widgetAsObject, QObject *new
widget->setParent(static_cast<QWidget*>(newParent));
}
+#ifndef QT_NO_DEBUG_STREAM
+
+static inline void formatWidgetAttributes(QDebug debug, const QWidget *widget)
+{
+ const QMetaObject *qtMo = qt_getEnumMetaObject(Qt::WA_AttributeCount);
+ const QMetaEnum me = qtMo->enumerator(qtMo->indexOfEnumerator("WidgetAttribute"));
+ debug << ", attributes=[";
+ int count = 0;
+ for (int a = 0; a < Qt::WA_AttributeCount; ++a) {
+ if (widget->testAttribute(static_cast<Qt::WidgetAttribute>(a))) {
+ if (count++)
+ debug << ',';
+ debug << me.valueToKey(a);
+ }
+ }
+ debug << ']';
+}
+
+QDebug operator<<(QDebug debug, const QWidget *widget)
+{
+ const QDebugStateSaver saver(debug);
+ debug.nospace();
+ if (widget) {
+ debug << widget->metaObject()->className() << '(' << (void *)widget;
+ if (!widget->objectName().isEmpty())
+ debug << ", name=" << widget->objectName();
+ if (debug.verbosity() > 2) {
+ const QRect geometry = widget->geometry();
+ const QRect frameGeometry = widget->frameGeometry();
+ if (widget->isVisible())
+ debug << ", visible";
+ if (!widget->isEnabled())
+ debug << ", disabled";
+ debug << ", states=" << widget->windowState()
+ << ", type=" << widget->windowType() << ", flags=" << widget->windowFlags();
+ formatWidgetAttributes(debug, widget);
+ if (widget->isWindow())
+ debug << ", window";
+ debug << ", " << geometry.width() << 'x' << geometry.height()
+ << forcesign << geometry.x() << geometry.y() << noforcesign;
+ if (frameGeometry != geometry) {
+ const QMargins margins(geometry.x() - frameGeometry.x(),
+ geometry.y() - frameGeometry.y(),
+ frameGeometry.right() - geometry.right(),
+ frameGeometry.bottom() - geometry.bottom());
+ debug << ", margins=" << margins;
+ }
+ debug << ", devicePixelRatio=" << widget->devicePixelRatio();
+ if (const WId wid = widget->internalWinId())
+ debug << ", winId=0x" << hex << wid << dec;
+ }
+ debug << ')';
+ } else {
+ debug << "QWidget(0x0)";
+ }
+ return debug;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
QT_END_NAMESPACE
#include "moc_qwidget.cpp"
diff --git a/src/widgets/kernel/qwidget.h b/src/widgets/kernel/qwidget.h
index c3913e9d45..782c892a32 100644
--- a/src/widgets/kernel/qwidget.h
+++ b/src/widgets/kernel/qwidget.h
@@ -89,6 +89,9 @@ class QGraphicsEffect;
class QRasterWindowSurface;
class QUnifiedToolbarSurface;
class QPixmap;
+#ifndef QT_NO_DEBUG_STREAM
+class QDebug;
+#endif
class QWidgetData
{
@@ -165,7 +168,7 @@ class Q_WIDGETS_EXPORT QWidget : public QObject, public QPaintDevice
Q_PROPERTY(bool acceptDrops READ acceptDrops WRITE setAcceptDrops)
Q_PROPERTY(QString windowTitle READ windowTitle WRITE setWindowTitle NOTIFY windowTitleChanged DESIGNABLE isWindow)
Q_PROPERTY(QIcon windowIcon READ windowIcon WRITE setWindowIcon NOTIFY windowIconChanged DESIGNABLE isWindow)
- Q_PROPERTY(QString windowIconText READ windowIconText WRITE setWindowIconText NOTIFY windowIconTextChanged DESIGNABLE isWindow)
+ Q_PROPERTY(QString windowIconText READ windowIconText WRITE setWindowIconText NOTIFY windowIconTextChanged DESIGNABLE isWindow) // deprecated
Q_PROPERTY(double windowOpacity READ windowOpacity WRITE setWindowOpacity DESIGNABLE isWindow)
Q_PROPERTY(bool windowModified READ isWindowModified WRITE setWindowModified DESIGNABLE isWindow)
#ifndef QT_NO_TOOLTIP
@@ -858,6 +861,10 @@ inline bool QWidget::testAttribute(Qt::WidgetAttribute attribute) const
#define QWIDGETSIZE_MAX ((1<<24)-1)
+#ifndef QT_NO_DEBUG_STREAM
+Q_WIDGETS_EXPORT QDebug operator<<(QDebug, const QWidget *);
+#endif
+
QT_END_NAMESPACE
#endif // QWIDGET_H
diff --git a/src/widgets/util/qsystemtrayicon_x11.cpp b/src/widgets/util/qsystemtrayicon_x11.cpp
index 2b153d53d9..2752c56c65 100644
--- a/src/widgets/util/qsystemtrayicon_x11.cpp
+++ b/src/widgets/util/qsystemtrayicon_x11.cpp
@@ -52,6 +52,8 @@
#include <private/qguiapplication_p.h>
#include <qdebug.h>
+#include <QtPlatformHeaders/qxcbwindowfunctions.h>
+#include <QtPlatformHeaders/qxcbintegrationfunctions.h>
#ifndef QT_NO_SYSTEMTRAYICON
QT_BEGIN_NAMESPACE
@@ -112,17 +114,11 @@ QSystemTrayIconSys::QSystemTrayIconSys(QSystemTrayIcon *qIn)
// window to ParentRelative (so that it inherits the background of its X11 parent window), call
// xcb_clear_region before painting (so that the inherited background is visible) and then grab
// the just-drawn background from the X11 server.
- bool hasAlphaChannel = false;
- QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
- "systrayVisualHasAlphaChannel", Qt::DirectConnection,
- Q_RETURN_ARG(bool, hasAlphaChannel));
+ bool hasAlphaChannel = QXcbIntegrationFunctions::xEmbedSystemTrayVisualHasAlphaChannel();
setAttribute(Qt::WA_TranslucentBackground, hasAlphaChannel);
if (!hasAlphaChannel) {
createWinId();
- QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
- "setParentRelativeBackPixmap", Qt::DirectConnection,
- Q_ARG(const QWindow *, windowHandle())
- );
+ QXcbWindowFunctions::setParentRelativeBackPixmap(windowHandle());
// XXX: This is actually required, but breaks things ("QWidget::paintEngine: Should no
// longer be called"). Why is this needed? When the widget is drawn, we use tricks to grab
@@ -143,15 +139,9 @@ bool QSystemTrayIconSys::addToTray()
createWinId();
setMouseTracking(true);
- bool requestResult = false;
- if (!QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
- "requestSystemTrayWindowDock", Qt::DirectConnection,
- Q_RETURN_ARG(bool, requestResult),
- Q_ARG(const QWindow *, windowHandle()))
- || !requestResult) {
- qWarning("requestSystemTrayWindowDock failed.");
+ if (!QXcbWindowFunctions::requestSystemTrayWindowDock(windowHandle()))
return false;
- }
+
if (!background.isNull())
background = QPixmap();
show();
@@ -171,15 +161,7 @@ void QSystemTrayIconSys::systemTrayWindowChanged(QScreen *)
QRect QSystemTrayIconSys::globalGeometry() const
{
- QRect result;
- if (!QMetaObject::invokeMethod(QGuiApplication::platformNativeInterface(),
- "systemTrayWindowGlobalGeometry", Qt::DirectConnection,
- Q_RETURN_ARG(QRect, result),
- Q_ARG(const QWindow *, windowHandle()))
- || !result.isValid()) {
- qWarning("systemTrayWindowGlobalGeometry failed.");
- }
- return result;
+ return QXcbWindowFunctions::systemTrayWindowGlobalGeometry(windowHandle());
}
void QSystemTrayIconSys::mousePressEvent(QMouseEvent *ev)
diff --git a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
index 32344f1e26..1b7d410beb 100644
--- a/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
+++ b/tests/auto/corelib/io/qdebug/tst_qdebug.cpp
@@ -49,6 +49,7 @@ private slots:
void debugWithBool() const;
void debugSpaceHandling() const;
void debugNoQuotes() const;
+ void verbosity() const;
void stateSaver() const;
void veryLongWarningMessage() const;
void qDebugQChar() const;
@@ -192,7 +193,11 @@ public:
QDebug operator<< (QDebug s, const MyLine& line)
{
const QDebugStateSaver saver(s);
- s.nospace() << "MyLine(" << line.p1 << ", " << line.p2 << ")";
+ s.nospace();
+ s << "MyLine(" << line.p1 << ", "<< line.p2;
+ if (s.verbosity() > 2)
+ s << ", Manhattan length=" << (qAbs(line.p2.v1 - line.p1.v1) + qAbs(line.p2.v2 - line.p1.v2));
+ s << ')';
return s;
}
@@ -255,6 +260,33 @@ void tst_QDebug::debugNoQuotes() const
QCOMPARE(s_msg, QString::fromLatin1("'H' \"Hello\" \"Hello\" H Hello Hello"));
}
+void tst_QDebug::verbosity() const
+{
+ MyLine line(MyPoint(10, 11), MyPoint (12, 13));
+ QString output;
+ QDebug d(&output);
+ d.nospace();
+ d << line << '\n';
+ const int oldVerbosity = d.verbosity();
+ d.setVerbosity(0);
+ QCOMPARE(d.verbosity(), 0);
+ d.setVerbosity(7);
+ QCOMPARE(d.verbosity(), 7);
+ const int newVerbosity = oldVerbosity + 2;
+ d.setVerbosity(newVerbosity);
+ QCOMPARE(d.verbosity(), newVerbosity);
+ d << line << '\n';
+ d.setVerbosity(oldVerbosity );
+ QCOMPARE(d.verbosity(), oldVerbosity );
+ d << line;
+ const QStringList lines = output.split(QLatin1Char('\n'));
+ QCOMPARE(lines.size(), 3);
+ // Verbose should be longer
+ QVERIFY2(lines.at(1).size() > lines.at(0).size(), qPrintable(lines.join(QLatin1Char(','))));
+ // Switching back to brief produces same output
+ QCOMPARE(lines.at(0).size(), lines.at(2).size());
+}
+
void tst_QDebug::stateSaver() const
{
MessageHandlerSetter mhs(myMessageHandler);
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+haiku/test b/tests/auto/corelib/io/qfileselector/platforms/+haiku/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+haiku/test
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+haiku/test2 b/tests/auto/corelib/io/qfileselector/platforms/+haiku/test2
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+haiku/test2
diff --git a/tests/auto/corelib/io/qfileselector/platforms/+unix/+haiku/test b/tests/auto/corelib/io/qfileselector/platforms/+unix/+haiku/test
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/auto/corelib/io/qfileselector/platforms/+unix/+haiku/test
diff --git a/tests/auto/corelib/io/qfileselector/qfileselector.qrc b/tests/auto/corelib/io/qfileselector/qfileselector.qrc
index 661647f933..6e2699774d 100644
--- a/tests/auto/corelib/io/qfileselector/qfileselector.qrc
+++ b/tests/auto/corelib/io/qfileselector/qfileselector.qrc
@@ -19,6 +19,7 @@
<file>platforms/+unix/+darwin/+mac/+osx/test</file>
<file>platforms/+unix/+darwin/+mac/test</file>
<file>platforms/+unix/+darwin/test</file>
+ <file>platforms/+unix/+haiku/test</file>
<file>platforms/+unix/+linux/test</file>
<file>platforms/+unix/test</file>
<file>platforms/+windows/+wince/test</file>
@@ -30,6 +31,7 @@
<file>platforms/+osx/test</file>
<file>platforms/+darwin/test</file>
<file>platforms/+mac/test</file>
+ <file>platforms/+haiku/test</file>
<file>platforms/+linux/test</file>
<file>platforms/+wince/test</file>
@@ -39,6 +41,7 @@
<file>platforms/+blackberry/test2</file>
<file>platforms/+ios/test2</file>
<file>platforms/+osx/test2</file>
+ <file>platforms/+haiku/test2</file>
<file>platforms/+linux/test2</file>
<file>platforms/+wince/test2</file>
<file>platforms/+winnt/test2</file>
diff --git a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp
index b3767b4887..87381f4c4e 100644
--- a/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp
+++ b/tests/auto/corelib/io/qfileselector/tst_qfileselector.cpp
@@ -89,7 +89,7 @@ void tst_QFileSelector::basicTest_data()
QString expectedPlatform2File(""); //Only the last selector
QString expectedPlatform3File; // Only the first selector (the family)
#if defined(Q_OS_UNIX) && !defined(Q_OS_ANDROID) && !defined(Q_OS_BLACKBERRY) && \
- !defined(Q_OS_DARWIN) && !defined(Q_OS_LINUX)
+ !defined(Q_OS_DARWIN) && !defined(Q_OS_LINUX) && !defined(Q_OS_HAIKU)
/* We are only aware of specific unixes, and do not have test files for any of the others.
However those unixes can get a selector added from the result of a uname call, so this will
lead to a case where we don't have that file so we can't expect the concatenation of platform
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index a192ccde59..6da8f55e61 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -3357,9 +3357,6 @@ void tst_QVariant::numericalConvert_data()
void tst_QVariant::numericalConvert()
{
-#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
- QSKIP("Known to fail due to a GCC bug on at least Ubuntu 10.04 32-bit - check QTBUG-8959");
-#endif
QFETCH(QVariant, v);
QFETCH(bool, isInteger);
double num = isInteger ? 5 : 5.3;
diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
index bdbb291d7f..cd77b188cc 100644
--- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
+++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
@@ -120,6 +120,7 @@ private slots:
void loadGarbage();
#endif
void relativePath();
+ void absolutePath();
void reloadPlugin();
void preloadedPlugin_data();
void preloadedPlugin();
@@ -406,6 +407,20 @@ void tst_QPluginLoader::relativePath()
QVERIFY(loader.unload());
}
+void tst_QPluginLoader::absolutePath()
+{
+ // Windows binaries run from release and debug subdirs, so we can't rely on the current dir.
+ const QString binDir = QFINDTESTDATA("bin");
+ QVERIFY(!binDir.isEmpty());
+ QVERIFY(QDir::isAbsolutePath(binDir));
+ QPluginLoader loader(binDir + "/theplugin");
+ loader.load(); // not recommended, instance() should do the job.
+ PluginInterface *instance = qobject_cast<PluginInterface*>(loader.instance());
+ QVERIFY(instance);
+ QCOMPARE(instance->pluginName(), QLatin1String("Plugin ok"));
+ QVERIFY(loader.unload());
+}
+
void tst_QPluginLoader::reloadPlugin()
{
QPluginLoader loader;
diff --git a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
index 7b1b7ce963..6e09ebb09b 100644
--- a/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
+++ b/tests/auto/corelib/tools/qcommandlineparser/testhelper/qcommandlineparser_test_helper.cpp
@@ -73,6 +73,12 @@ int main(int argc, char *argv[])
"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"));
parser.addOption(newlineOption);
+ // A hidden option
+ QCommandLineOption hiddenOption(QStringList() << QStringLiteral("hidden"));
+ hiddenOption.setDescription(QStringLiteral("THIS SHOULD NEVER APPEAR"));
+ hiddenOption.setHidden(true);
+ parser.addOption(hiddenOption);
+
// This program supports different options depending on the "command" (first argument).
// Call parse() to find out the positional arguments.
parser.parse(QCoreApplication::arguments());
diff --git a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
index 6ff46ed20b..9c4ded69de 100644
--- a/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
+++ b/tests/auto/corelib/tools/qcommandlineparser/tst_qcommandlineparser.cpp
@@ -35,6 +35,7 @@
#include <QtCore/QCommandLineParser>
Q_DECLARE_METATYPE(char**)
+Q_DECLARE_METATYPE(QCommandLineParser::OptionsAfterPositionalArgumentsMode)
class tst_QCommandLineParser : public QObject
{
@@ -51,6 +52,8 @@ private slots:
void testPositionalArguments();
void testBooleanOption_data();
void testBooleanOption();
+ void testOptionsAndPositional_data();
+ void testOptionsAndPositional();
void testMultipleNames_data();
void testMultipleNames();
void testSingleValueOption_data();
@@ -141,6 +144,40 @@ void tst_QCommandLineParser::testBooleanOption()
QVERIFY(!parser.isSet("c"));
}
+void tst_QCommandLineParser::testOptionsAndPositional_data()
+{
+ QTest::addColumn<QStringList>("args");
+ QTest::addColumn<QStringList>("expectedOptionNames");
+ QTest::addColumn<bool>("expectedIsSet");
+ QTest::addColumn<QStringList>("expectedPositionalArguments");
+ QTest::addColumn<QCommandLineParser::OptionsAfterPositionalArgumentsMode>("parsingMode");
+
+ const QStringList arg = QStringList() << "arg";
+ QTest::newRow("before_positional_default") << (QStringList() << "tst_qcommandlineparser" << "-b" << "arg") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsOptions;
+ QTest::newRow("after_positional_default") << (QStringList() << "tst_qcommandlineparser" << "arg" << "-b") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsOptions;
+ QTest::newRow("before_positional_parseAsArg") << (QStringList() << "tst_qcommandlineparser" << "-b" << "arg") << (QStringList() << "b") << true << arg << QCommandLineParser::ParseAsPositionalArguments;
+ QTest::newRow("after_positional_parseAsArg") << (QStringList() << "tst_qcommandlineparser" << "arg" << "-b") << (QStringList()) << false << (QStringList() << "arg" << "-b") << QCommandLineParser::ParseAsPositionalArguments;
+}
+
+void tst_QCommandLineParser::testOptionsAndPositional()
+{
+ QFETCH(QStringList, args);
+ QFETCH(QStringList, expectedOptionNames);
+ QFETCH(bool, expectedIsSet);
+ QFETCH(QStringList, expectedPositionalArguments);
+ QFETCH(QCommandLineParser::OptionsAfterPositionalArgumentsMode, parsingMode);
+
+ QCoreApplication app(empty_argc, empty_argv);
+ QCommandLineParser parser;
+ parser.setOptionsAfterPositionalArgumentsMode(parsingMode);
+ QVERIFY(parser.addOption(QCommandLineOption(QStringLiteral("b"), QStringLiteral("a boolean option"))));
+ QVERIFY(parser.parse(args));
+ QCOMPARE(parser.optionNames(), expectedOptionNames);
+ QCOMPARE(parser.isSet("b"), expectedIsSet);
+ QCOMPARE(parser.values("b"), QStringList());
+ QCOMPARE(parser.positionalArguments(), expectedPositionalArguments);
+}
+
void tst_QCommandLineParser::testMultipleNames_data()
{
QTest::addColumn<QStringList>("args");
diff --git a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
index 8c29064457..33e143fa7d 100644
--- a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
+++ b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp
@@ -60,7 +60,7 @@ void tst_QRingBuffer::sizeWhenReserved()
QRingBuffer ringBuffer;
ringBuffer.reserve(5);
- QCOMPARE(ringBuffer.size(), 5);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(5));
}
void tst_QRingBuffer::sizeWhenReservedAndChopped()
@@ -69,14 +69,14 @@ void tst_QRingBuffer::sizeWhenReservedAndChopped()
ringBuffer.reserve(31337);
ringBuffer.chop(31337);
- QCOMPARE(ringBuffer.size(), 0);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
void tst_QRingBuffer::sizeWhenEmpty()
{
QRingBuffer ringBuffer;
- QCOMPARE(ringBuffer.size(), 0);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(0));
}
void tst_QRingBuffer::readPointerAtPositionReadTooMuch()
@@ -101,22 +101,22 @@ void tst_QRingBuffer::readPointerAtPositionWithHead()
qint64 length;
const char* buf2 = ringBuffer.readPointerAtPosition(0, length);
- QCOMPARE(length, qint64(2));
+ QCOMPARE(length, Q_INT64_C(2));
QVERIFY(*buf2 == '2');
QVERIFY(*(buf2+1) == '3');
// advance 2 more, ringBuffer should be empty then
ringBuffer.free(2);
buf2 = ringBuffer.readPointerAtPosition(0, length);
- QCOMPARE(length, qint64(0));
+ QCOMPARE(length, Q_INT64_C(0));
QVERIFY(buf2 == 0);
// check buffer with 2 blocks
memcpy(ringBuffer.reserve(4), "0123", 4);
ringBuffer.append(QByteArray("45678", 5));
ringBuffer.free(3);
- buf2 = ringBuffer.readPointerAtPosition(1, length);
- QCOMPARE(length, qint64(5));
+ buf2 = ringBuffer.readPointerAtPosition(Q_INT64_C(1), length);
+ QCOMPARE(length, Q_INT64_C(5));
}
void tst_QRingBuffer::readPointerAtPositionEmptyRead()
@@ -149,14 +149,14 @@ void tst_QRingBuffer::readPointerAtPositionWriteRead()
// write in chunks of 50 bytes
// this ensures there will be multiple QByteArrays inside the QRingBuffer
// since QRingBuffer is then only using individual arrays of around 4000 bytes
- qint64 thisWrite = qMin(remaining, qint64(50));
+ qint64 thisWrite = qMin(remaining, Q_INT64_C(50));
char *pos = ringBuffer.reserve(thisWrite);
inData.read(pos, thisWrite);
remaining -= thisWrite;
}
// was data put into it?
QVERIFY(ringBuffer.size() > 0);
- QCOMPARE(qint64(ringBuffer.size()), inData.size());
+ QCOMPARE(ringBuffer.size(), inData.size());
//read from the QRingBuffer in loop, put back into another QBuffer
QBuffer outData;
@@ -187,12 +187,12 @@ void tst_QRingBuffer::free()
ringBuffer.append(QByteArray("01234", 5));
ringBuffer.free(1);
- QCOMPARE(ringBuffer.size(), 4095 + 2048 + 5);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(4095 + 2048 + 5));
ringBuffer.free(4096);
- QCOMPARE(ringBuffer.size(), 2047 + 5);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(2047 + 5));
ringBuffer.free(48);
ringBuffer.free(2000);
- QCOMPARE(ringBuffer.size(), 4);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
QVERIFY(memcmp(ringBuffer.readPointer(), "1234", 4) == 0);
}
@@ -211,8 +211,8 @@ void tst_QRingBuffer::reserveAndRead()
for (int i = 1; i < 256; ++i) {
QByteArray ba;
ba.resize(i);
- int thisRead = ringBuffer.read(ba.data(), i);
- QCOMPARE(thisRead, i);
+ qint64 thisRead = ringBuffer.read(ba.data(), i);
+ QCOMPARE(thisRead, qint64(i));
QVERIFY(ba.count(char(i)) == i);
}
QVERIFY(ringBuffer.size() == 0);
@@ -227,12 +227,12 @@ void tst_QRingBuffer::chop()
ringBuffer.reserve(4096);
ringBuffer.chop(1);
- QCOMPARE(ringBuffer.size(), 5 + 2048 + 4095);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2048 + 4095));
ringBuffer.chop(4096);
- QCOMPARE(ringBuffer.size(), 5 + 2047);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(5 + 2047));
ringBuffer.chop(48);
ringBuffer.chop(2000);
- QCOMPARE(ringBuffer.size(), 4);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(4));
QVERIFY(memcmp(ringBuffer.readPointer(), "0123", 4) == 0);
}
@@ -248,7 +248,7 @@ void tst_QRingBuffer::ungetChar()
ringBuffer.getChar();
ringBuffer.ungetChar(char(c)); // unget first char
}
- QCOMPARE(ringBuffer.size(), 1);
+ QCOMPARE(ringBuffer.size(), Q_INT64_C(1));
}
void tst_QRingBuffer::indexOf()
@@ -258,8 +258,8 @@ void tst_QRingBuffer::indexOf()
ringBuffer.putChar(char(i));
for (int i = 1; i < 256; ++i) {
- int index = ringBuffer.indexOf(char(i));
- QCOMPARE(i - 1, index);
+ qint64 index = ringBuffer.indexOf(char(i));
+ QCOMPARE(qint64(i - 1), index);
QCOMPARE(index, ringBuffer.indexOf(char(i), i));
QVERIFY(ringBuffer.indexOf(char(i), i - 1) == -1); // test for absent char
}
@@ -298,7 +298,7 @@ void tst_QRingBuffer::readLine()
// check first empty string reading
stringBuf[0] = char(0xFF);
- QCOMPARE(ringBuffer.readLine(stringBuf, int(sizeof(stringBuf)) - 2), ba2.size());
+ QCOMPARE(ringBuffer.readLine(stringBuf, int(sizeof(stringBuf)) - 2), qint64(ba2.size()));
QVERIFY(stringBuf[0] == ba2[0]);
QVERIFY(ringBuffer.readLine(stringBuf, int(sizeof(stringBuf)) - 2) == (ba3.size() + ba4.size()
diff --git a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
index 32c228c186..d85e842a23 100644
--- a/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
+++ b/tests/auto/dbus/qdbusconnection/tst_qdbusconnection.cpp
@@ -105,6 +105,8 @@ private slots:
void sendWithGui();
void sendAsync();
void sendSignal();
+ void sendSignalToName();
+ void sendSignalToOtherName();
void registerObject_data();
void registerObject();
@@ -189,6 +191,49 @@ void tst_QDBusConnection::sendSignal()
QTest::qWait(1000);
}
+void tst_QDBusConnection::sendSignalToName()
+{
+ QDBusSpy spy;
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ con.connect(con.baseService(), "/org/kde/selftest", "org.kde.selftest", "ping", &spy,
+ SLOT(handlePing(QString)));
+
+ QDBusMessage msg =
+ QDBusMessage::createTargetedSignal(con.baseService(), "/org/kde/selftest",
+ "org.kde.selftest", "ping");
+ msg << QLatin1String("ping");
+
+ QVERIFY(con.send(msg));
+
+ QTest::qWait(1000);
+
+ QCOMPARE(spy.args.count(), 1);
+ QCOMPARE(spy.args.at(0).toString(), QString("ping"));
+}
+
+void tst_QDBusConnection::sendSignalToOtherName()
+{
+ QDBusSpy spy;
+
+ QDBusConnection con = QDBusConnection::sessionBus();
+
+ con.connect(con.baseService(), "/org/kde/selftest", "org.kde.selftest", "ping", &spy,
+ SLOT(handlePing(QString)));
+
+ QDBusMessage msg =
+ QDBusMessage::createTargetedSignal("some.other.service", "/org/kde/selftest",
+ "org.kde.selftest", "ping");
+ msg << QLatin1String("ping");
+
+ QVERIFY(con.send(msg));
+
+ QTest::qWait(1000);
+
+ QCOMPARE(spy.args.count(), 0);
+}
+
void tst_QDBusConnection::send()
{
QDBusConnection con = QDBusConnection::sessionBus();
diff --git a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
index 4fafbf9827..7d17794c0b 100644
--- a/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
+++ b/tests/auto/gui/painting/qcolor/tst_qcolor.cpp
@@ -38,6 +38,7 @@
#include <qcolor.h>
#include <qdebug.h>
+#include <qrgba64.h>
#include <private/qdrawingprimitive_sse2_p.h>
class tst_QColor : public QObject
@@ -105,6 +106,9 @@ private slots:
void premultiply();
void unpremultiply_sse4();
+ void qrgba64();
+ void qrgba64Premultiply();
+ void qrgba64Equivalence();
#ifdef Q_DEAD_CODE_FROM_QT4_X11
void setallowX11ColorNames();
@@ -1455,7 +1459,7 @@ void tst_QColor::unpremultiply_sse4()
for (uint a = 0; a < 256; a++) {
for (uint c = 0; c <= a; c++) {
QRgb p = qRgba(c, a-c, c, a);
- QCOMPARE(qUnpremultiply(p), qUnpremultiply_sse4(p));
+ QCOMPARE(qUnpremultiply_sse4(p), qUnpremultiply(p));
}
}
return;
@@ -1464,5 +1468,84 @@ void tst_QColor::unpremultiply_sse4()
QSKIP("SSE4 not supported on this CPU.");
}
+void tst_QColor::qrgba64()
+{
+ QRgba64 rgb64 = QRgba64::fromRgba(0x22, 0x33, 0x44, 0xff);
+ QCOMPARE(rgb64.red(), quint16(0x2222));
+ QCOMPARE(rgb64.green(), quint16(0x3333));
+ QCOMPARE(rgb64.blue(), quint16(0x4444));
+ QCOMPARE(rgb64.alpha(), quint16(0xffff));
+
+ QColor c(rgb64);
+ QCOMPARE(c.red(), 0x22);
+ QCOMPARE(c.green(), 0x33);
+ QCOMPARE(c.blue(), 0x44);
+
+ QCOMPARE(c.rgba64(), rgb64);
+
+ QColor c2 = QColor::fromRgb(0x22, 0x33, 0x44, 0xff);
+ QCOMPARE(c, c2);
+ QCOMPARE(c2.rgba64(), rgb64);
+
+ rgb64.setAlpha(0x8000);
+ rgb64.setGreen(0x8844);
+ rgb64 = rgb64.premultiplied();
+ QCOMPARE(rgb64.red(), quint16(0x1111));
+ QCOMPARE(rgb64.blue(), quint16(0x2222));
+ QCOMPARE(rgb64.green(), quint16(0x4422));
+}
+
+void tst_QColor::qrgba64Premultiply()
+{
+ // Tests that qPremultiply(qUnpremultiply(rgba64)) returns rgba64.
+ for (uint a = 0; a < 0x10000; a+=7) {
+ const uint step = std::max(a/1024, 1u);
+ for (uint c = 0; c <= a; c+=step) {
+ QRgba64 p = qRgba64(c, a-c, a-c/2, a);
+ QRgba64 pp = qPremultiply(qUnpremultiply(p));
+ QCOMPARE(pp, p);
+ }
+ }
+}
+
+void tst_QColor::qrgba64Equivalence()
+{
+ // Any ARGB32 converted back and forth.
+ for (uint a = 0; a < 256; a++) {
+ for (uint c = 0; c < 256; c++) {
+ QRgb p1 = qRgba(c, 255-c, 255-c, a);
+ QRgba64 p64 = QRgba64::fromArgb32(p1);
+ QCOMPARE(p64.toArgb32(), p1);
+ }
+ }
+ // Any unpremultiplied ARGB32 value premultipled in RGB64 (except alpha 0).
+ for (uint a = 1; a < 256; a++) {
+ for (uint c = 0; c < 256; c++) {
+ QRgb p1 = qRgba(c, 255-c, 255-c, a);
+ QRgb pp1 = qPremultiply(p1);
+ QRgba64 pp64 = qPremultiply(QRgba64::fromArgb32(p1));
+ QRgb pp2 = pp64.toArgb32();
+ // 64bit premultiplied is more accurate than 32bit, so allow slight difference.
+ QCOMPARE(qAlpha(pp2), qAlpha(pp1));
+ QVERIFY(qAbs(qRed(pp2)-qRed(pp1)) <= 1);
+ QVERIFY(qAbs(qGreen(pp2)-qGreen(pp1)) <= 1);
+ QVERIFY(qAbs(qBlue(pp2)-qBlue(pp1)) <= 1);
+ // But verify the added accuracy means we can return to accurate unpremultiplied ARGB32.
+ QRgba64 pu64 = qUnpremultiply(pp64);
+ QRgb p2 = pu64.toArgb32();
+ QCOMPARE(p2, p1);
+ }
+ }
+ // Any premultiplied ARGB32 value unpremultipled in RGB64.
+ for (uint a = 0; a < 256; a++) {
+ for (uint c = 0; c <= a; c++) {
+ QRgb pp = qRgba(c, a-c, a-c, a);
+ QRgb pu = qUnpremultiply(pp);
+ QRgba64 pu64 = qUnpremultiply(QRgba64::fromArgb32(pp));
+ QCOMPARE(pu64.toArgb32(), pu);
+ }
+ }
+}
+
QTEST_MAIN(tst_QColor)
#include "tst_qcolor.moc"
diff --git a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
index c63cfaf6b6..dcb3df834d 100644
--- a/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
+++ b/tests/auto/network/access/qnetworkreply/tst_qnetworkreply.cpp
@@ -121,6 +121,14 @@ class tst_QNetworkReply: public QObject
return s;
};
+ static QString tempRedirectReplyStr() {
+ QString s = "HTTP/1.1 307 Temporary Redirect\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: %1\r\n"
+ "\r\n";
+ return s;
+ };
+
QEventLoop *loop;
enum RunSimpleRequestReturn { Timeout = 0, Success, Failure };
int returnCode;
@@ -456,6 +464,11 @@ private Q_SLOTS:
void putWithRateLimiting();
+ void ioHttpSingleRedirect();
+ void ioHttpChangeMaxRedirects();
+ void ioHttpRedirectErrors_data();
+ void ioHttpRedirectErrors();
+
// NOTE: This test must be last!
void parentingRepliesToTheApp();
private:
@@ -593,10 +606,16 @@ protected:
virtual void reply() {
Q_ASSERT(!client.isNull());
// we need to emulate the bytesWrittenSlot call if the data is empty.
- if (dataToTransmit.size() == 0)
+ if (dataToTransmit.size() == 0) {
QMetaObject::invokeMethod(this, "bytesWrittenSlot", Qt::QueuedConnection);
- else
+ } else {
client->write(dataToTransmit);
+ // FIXME: For SSL connections, if we don't flush the socket, the
+ // client never receives the data and since we're doing a disconnect
+ // immediately afterwards, it causes a RemoteHostClosedError for the
+ // client
+ client->flush();
+ }
}
private:
void connectSocketSignals()
@@ -7962,7 +7981,142 @@ void tst_QNetworkReply::putWithRateLimiting()
QCOMPARE(uploadedData, data);
}
+void tst_QNetworkReply::ioHttpSingleRedirect()
+{
+ QUrl localhost = QUrl("http://localhost");
+ QByteArray http200Reply = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
+
+ // Setup server to which the second server will redirect to
+ MiniHttpServer server2(http200Reply);
+
+ QUrl redirectUrl = QUrl(localhost);
+ redirectUrl.setPort(server2.serverPort());
+
+ QByteArray tempRedirectReply =
+ tempRedirectReplyStr().arg(QString(redirectUrl.toEncoded())).toLatin1();
+
+
+ // Setup redirect server
+ MiniHttpServer server(tempRedirectReply);
+
+ localhost.setPort(server.serverPort());
+ QNetworkRequest request(localhost);
+ request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+
+ QNetworkReplyPtr reply(manager.get(request));
+ QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl)));
+ QSignalSpy finSpy(reply.data(), SIGNAL(finished()));
+
+ QVERIFY2(waitForFinish(reply) == Success, msgWaitForFinished(reply));
+
+ // Redirected and finished should be emitted exactly once
+ QCOMPARE(redSpy.count(), 1);
+ QCOMPARE(finSpy.count(), 1);
+
+ // Original URL should not be changed after redirect
+ QCOMPARE(request.url(), localhost);
+
+ // Verify Redirect url
+ QList<QVariant> args = redSpy.takeFirst();
+ QCOMPARE(args.at(0).toUrl(), redirectUrl);
+
+ // Reply url is set to the redirect url
+ QCOMPARE(reply->url(), redirectUrl);
+ QCOMPARE(reply->error(), QNetworkReply::NoError);
+}
+
+void tst_QNetworkReply::ioHttpChangeMaxRedirects()
+{
+ QUrl localhost = QUrl("http://localhost");
+ QByteArray http200Reply = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n";
+
+ MiniHttpServer server1("");
+ MiniHttpServer server2("");
+ MiniHttpServer server3(http200Reply);
+
+ QUrl server2Url(localhost);
+ server2Url.setPort(server2.serverPort());
+ server1.setDataToTransmit(tempRedirectReplyStr().arg(
+ QString(server2Url.toEncoded())).toLatin1());
+
+ QUrl server3Url(localhost);
+ server3Url.setPort(server3.serverPort());
+ server2.setDataToTransmit(tempRedirectReplyStr().arg(
+ QString(server3Url.toEncoded())).toLatin1());
+
+ localhost.setPort(server1.serverPort());
+ QNetworkRequest request(localhost);
+ request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+
+ // Set Max redirects to 1. This will cause TooManyRedirectsError
+ request.setMaximumRedirectsAllowed(1);
+
+ QNetworkReplyPtr reply(manager.get(request));
+ QSignalSpy redSpy(reply.data(), SIGNAL(redirected(QUrl)));
+ QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
+
+ QVERIFY(waitForFinish(reply) == Failure);
+
+ QCOMPARE(redSpy.count(), request.maximumRedirectsAllowed());
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(reply->error() == QNetworkReply::TooManyRedirectsError);
+
+ // Increase max redirects to allow successful completion
+ request.setMaximumRedirectsAllowed(3);
+
+ QNetworkReplyPtr reply2(manager.get(request));
+ QSignalSpy redSpy2(reply2.data(), SIGNAL(redirected(QUrl)));
+
+ QVERIFY2(waitForFinish(reply2) == Success, msgWaitForFinished(reply2));
+
+ QCOMPARE(redSpy2.count(), 2);
+ QCOMPARE(reply2->url(), server3Url);
+ QVERIFY(reply2->error() == QNetworkReply::NoError);
+}
+
+void tst_QNetworkReply::ioHttpRedirectErrors_data()
+{
+ QTest::addColumn<QString>("url");
+ QTest::addColumn<QString>("dataToSend");
+ QTest::addColumn<QNetworkReply::NetworkError>("error");
+
+ QString tempRedirectReply = QString("HTTP/1.1 307 Temporary Redirect\r\n"
+ "Content-Type: text/plain\r\n"
+ "location: http://localhost:%1\r\n\r\n");
+
+ QTest::newRow("too-many-redirects") << "http://localhost" << tempRedirectReply << QNetworkReply::TooManyRedirectsError;
+ QTest::newRow("insecure-redirect") << "https://localhost" << tempRedirectReply << QNetworkReply::InsecureRedirectError;
+ QTest::newRow("unknown-redirect") << "http://localhost"<< tempRedirectReply.replace("http", "bad_protocol") << QNetworkReply::ProtocolUnknownError;
+}
+
+void tst_QNetworkReply::ioHttpRedirectErrors()
+{
+ QFETCH(QString, url);
+ QFETCH(QString, dataToSend);
+ QFETCH(QNetworkReply::NetworkError, error);
+
+ QUrl localhost(url);
+ MiniHttpServer server("", localhost.scheme() == "https");
+
+ localhost.setPort(server.serverPort());
+
+ QByteArray d2s = dataToSend.arg(
+ QString::number(server.serverPort())).toLatin1();
+ server.setDataToTransmit(d2s);
+
+ QNetworkRequest request(localhost);
+ request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+ QNetworkReplyPtr reply(manager.get(request));
+ if (localhost.scheme() == "https")
+ reply.data()->ignoreSslErrors();
+ QSignalSpy spy(reply.data(), SIGNAL(error(QNetworkReply::NetworkError)));
+
+ QVERIFY(waitForFinish(reply) == Failure);
+
+ QCOMPARE(spy.count(), 1);
+ QVERIFY(reply->error() == error);
+}
// NOTE: This test must be last testcase in tst_qnetworkreply!
void tst_QNetworkReply::parentingRepliesToTheApp()
diff --git a/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp
index 76c36831bd..1c79b6c016 100644
--- a/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp
+++ b/tests/auto/network/socket/qabstractsocket/tst_qabstractsocket.cpp
@@ -37,11 +37,6 @@
#include <qcoreapplication.h>
#include <qdebug.h>
#include <qabstractsocket.h>
-#include <qtcpserver.h>
-#include <qtcpsocket.h>
-#ifndef QT_NO_SSL
-#include <qsslsocket.h>
-#endif
class tst_QAbstractSocket : public QObject
{
@@ -52,9 +47,7 @@ public:
virtual ~tst_QAbstractSocket();
private slots:
- void initTestCase();
void getSetCheck();
- void serverDisconnectWithBuffered();
};
tst_QAbstractSocket::tst_QAbstractSocket()
@@ -73,11 +66,6 @@ public:
void setPeerPort(quint16 port) { QAbstractSocket::setPeerPort(port); }
};
-void tst_QAbstractSocket::initTestCase()
-{
- qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
-}
-
// Testing get/set functions
void tst_QAbstractSocket::getSetCheck()
{
@@ -106,46 +94,5 @@ void tst_QAbstractSocket::getSetCheck()
QCOMPARE(quint16(0xffff), obj1.peerPort());
}
-// Test buffered socket being properly closed on remote disconnect
-void tst_QAbstractSocket::serverDisconnectWithBuffered()
-{
- QTcpServer tcpServer;
-#ifndef QT_NO_SSL
- QSslSocket testSocket;
-#else
- QTcpSocket testSocket;
-#endif
-
- QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
- testSocket.connectToHost(tcpServer.serverAddress(), tcpServer.serverPort());
- // Accept connection on server side
- QVERIFY(tcpServer.waitForNewConnection(5000));
- QTcpSocket *newConnection = tcpServer.nextPendingConnection();
- // Send one char and drop link
- QVERIFY(newConnection != NULL);
- QVERIFY(newConnection->putChar(0));
- QVERIFY(newConnection->flush());
- delete newConnection;
-
- QVERIFY(testSocket.waitForConnected(5000)); // ready for write
- QVERIFY(testSocket.state() == QAbstractSocket::ConnectedState);
-
- QSignalSpy spyStateChanged(&testSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
- QSignalSpy spyDisconnected(&testSocket, SIGNAL(disconnected()));
-
- QVERIFY(testSocket.waitForReadyRead(5000)); // have one char already in internal buffer
- char buf[128];
- QCOMPARE(testSocket.read(buf, sizeof(buf)), Q_INT64_C(1));
- if (testSocket.state() != QAbstractSocket::UnconnectedState) {
- QVERIFY(testSocket.waitForDisconnected(5000));
- QVERIFY(testSocket.state() == QAbstractSocket::UnconnectedState);
- }
- // Test signal emitting
- QVERIFY(spyDisconnected.count() == 1);
- QVERIFY(spyStateChanged.count() > 0);
- QVERIFY(qvariant_cast<QAbstractSocket::SocketState>(spyStateChanged.last().first())
- == QAbstractSocket::UnconnectedState);
-}
-
QTEST_MAIN(tst_QAbstractSocket)
#include "tst_qabstractsocket.moc"
diff --git a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
index 0ba9b6a58c..109e48ed74 100644
--- a/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
+++ b/tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
@@ -200,6 +200,7 @@ private slots:
void setSocketOption();
void clientSendDataOnDelayedDisconnect();
+ void serverDisconnectWithBuffered();
protected slots:
void nonBlockingIMAP_hostFound();
@@ -2984,5 +2985,50 @@ void tst_QTcpSocket::clientSendDataOnDelayedDisconnect()
delete socket;
}
+// Test buffered socket being properly closed on remote disconnect
+void tst_QTcpSocket::serverDisconnectWithBuffered()
+{
+ QFETCH_GLOBAL(bool, setProxy);
+ if (setProxy)
+ return;
+
+ qRegisterMetaType<QAbstractSocket::SocketState>("QAbstractSocket::SocketState");
+
+ QTcpServer tcpServer;
+ QTcpSocket *socket = newSocket();
+
+ QVERIFY(tcpServer.listen(QHostAddress::LocalHost));
+ socket->connectToHost(tcpServer.serverAddress(), tcpServer.serverPort());
+ // Accept connection on server side
+ QVERIFY(tcpServer.waitForNewConnection(5000));
+ QTcpSocket *newConnection = tcpServer.nextPendingConnection();
+ // Send one char and drop link
+ QVERIFY(newConnection != NULL);
+ QVERIFY(newConnection->putChar(0));
+ QVERIFY(newConnection->flush());
+ delete newConnection;
+
+ QVERIFY(socket->waitForConnected(5000)); // ready for write
+ QVERIFY(socket->state() == QAbstractSocket::ConnectedState);
+
+ QSignalSpy spyStateChanged(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)));
+ QSignalSpy spyDisconnected(socket, SIGNAL(disconnected()));
+
+ QVERIFY(socket->waitForReadyRead(5000)); // have one char already in internal buffer
+ char buf[128];
+ QCOMPARE(socket->read(buf, sizeof(buf)), Q_INT64_C(1));
+ if (socket->state() != QAbstractSocket::UnconnectedState) {
+ QVERIFY(socket->waitForDisconnected(5000));
+ QVERIFY(socket->state() == QAbstractSocket::UnconnectedState);
+ }
+ // Test signal emitting
+ QVERIFY(spyDisconnected.count() == 1);
+ QVERIFY(spyStateChanged.count() > 0);
+ QVERIFY(qvariant_cast<QAbstractSocket::SocketState>(spyStateChanged.last().first())
+ == QAbstractSocket::UnconnectedState);
+
+ delete socket;
+}
+
QTEST_MAIN(tst_QTcpSocket)
#include "tst_qtcpsocket.moc"
diff --git a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
index 9937b6f7f8..8061b1ccb9 100644
--- a/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
+++ b/tests/auto/other/qaccessibility/tst_qaccessibility.cpp
@@ -668,7 +668,7 @@ void tst_QAccessibility::textAttributes_data()
defaultComplexFont.setStyle(QFont::StyleItalic);
defaultComplexFont.setUnderline(true);
- static QStringList defaults = QString("font-style:normal;font-weight:normal;text-align:left;text-position:baseline;text-underline-style:none;font-size:13pt").split(';');
+ static QStringList defaults = QString("font-style:normal;font-weight:normal;text-align:left;text-position:baseline;font-size:13pt").split(';');
static QStringList bold = defaults;
bold[1] = QString::fromLatin1("font-weight:bold");
@@ -683,7 +683,7 @@ void tst_QAccessibility::textAttributes_data()
monospace.append(QLatin1String("font-family:\"monospace\""));
static QStringList font8pt = defaults;
- font8pt[5] = (QLatin1String("font-size:8pt"));
+ font8pt[4] = (QLatin1String("font-size:8pt"));
static QStringList color = defaults;
color << QLatin1String("color:rgb(240,241,242)") << QLatin1String("background-color:rgb(20,240,30)");
@@ -694,8 +694,9 @@ void tst_QAccessibility::textAttributes_data()
static QStringList defaultFontDifferent = defaults;
defaultFontDifferent[0] = QString::fromLatin1("font-style:italic");
defaultFontDifferent[1] = QString::fromLatin1("font-weight:bold");
- defaultFontDifferent[4] = QString::fromLatin1("text-underline-style:solid");
- defaultFontDifferent[5] = QString::fromLatin1("font-size:20pt");
+ defaultFontDifferent[4] = QString::fromLatin1("font-size:20pt");
+ defaultFontDifferent.append("text-underline-style:solid");
+ defaultFontDifferent.append("text-underline-type:single");
defaultFontDifferent.append("font-family:\"Arial\"");
static QStringList defaultFontDifferentBoldItalic = defaultFontDifferent;
@@ -703,10 +704,10 @@ void tst_QAccessibility::textAttributes_data()
defaultFontDifferentBoldItalic[1] = QString::fromLatin1("font-weight:bold");
static QStringList defaultFontDifferentMonospace = defaultFontDifferent;
- defaultFontDifferentMonospace[6] = (QLatin1String("font-family:\"monospace\""));
+ defaultFontDifferentMonospace[7] = (QLatin1String("font-family:\"monospace\""));
static QStringList defaultFontDifferentFont8pt = defaultFontDifferent;
- defaultFontDifferentFont8pt[5] = (QLatin1String("font-size:8pt"));
+ defaultFontDifferentFont8pt[4] = (QLatin1String("font-size:8pt"));
static QStringList defaultFontDifferentColor = defaultFontDifferent;
defaultFontDifferentColor << QLatin1String("color:rgb(240,241,242)") << QLatin1String("background-color:rgb(20,240,30)");
@@ -1715,7 +1716,10 @@ static QRect characterRect(const QTextEdit &edit, int offset)
QPointF layoutPosition = layout->position();
int relativeOffset = offset - block.position();
QTextLine line = layout->lineForTextPosition(relativeOffset);
- QFontMetrics fm(edit.currentFont());
+ QTextBlock::iterator it = block.begin();
+ while (!it.fragment().contains(offset))
+ ++it;
+ QFontMetrics fm(it.fragment().charFormat().font());
QChar ch = edit.document()->characterAt(offset);
int w = fm.width(ch);
int h = fm.height();
@@ -1747,6 +1751,7 @@ void tst_QAccessibility::textEditTest()
for (int pass = 0; pass < 2; ++pass) {
{
QTextEdit edit;
+ edit.setMinimumSize(600, 400);
setFrameless(&edit);
int startOffset;
int endOffset;
@@ -1757,7 +1762,7 @@ void tst_QAccessibility::textEditTest()
QFont font("Helvetica");
font.setPointSizeF(12.5);
font.setWordSpacing(1.1);
- edit.setCurrentFont(font);
+ edit.document()->setDefaultFont(font);
}
edit.show();
@@ -1779,7 +1784,7 @@ void tst_QAccessibility::textEditTest()
QCOMPARE(startOffset, 13);
QCOMPARE(endOffset, 31);
QCOMPARE(textIface->characterCount(), 48);
- QFontMetrics fm(edit.currentFont());
+ QFontMetrics fm(edit.document()->defaultFont());
QCOMPARE(textIface->characterRect(0).size(), QSize(fm.width("h"), fm.height()));
QCOMPARE(textIface->characterRect(5).size(), QSize(fm.width(" "), fm.height()));
QCOMPARE(textIface->characterRect(6).size(), QSize(fm.width("w"), fm.height()));
diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp
index 8e439a61cf..92af5a0757 100644
--- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac.cpp
@@ -75,6 +75,7 @@ private slots:
void lineEditTest();
void hierarchyTest();
void notificationsTest();
+ void checkBoxTest();
private:
AccessibleTestWindow *m_window;
@@ -151,5 +152,19 @@ void tst_QAccessibilityMac::notificationsTest()
QVERIFY(notifications(m_window));
}
+void tst_QAccessibilityMac::checkBoxTest()
+{
+ if (!macNativeAccessibilityEnabled())
+ return;
+
+ QCheckBox *cb = new QCheckBox(m_window);
+ cb->setText("Great option");
+ m_window->addWidget(cb);
+ QVERIFY(QTest::qWaitForWindowExposed(m_window));
+ QCoreApplication::processEvents();
+
+ QVERIFY(testCheckBox());
+}
+
QTEST_MAIN(tst_QAccessibilityMac)
#include "tst_qaccessibilitymac.moc"
diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h
index 78615fa9cd..cdf12489a6 100644
--- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.h
@@ -44,3 +44,4 @@ bool testLineEdit();
bool testHierarchy(QWidget *w);
bool singleWidget();
bool notifications(QWidget *w);
+bool testCheckBox();
diff --git a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm
index b004e985bd..d0ff6af640 100644
--- a/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm
+++ b/tests/auto/other/qaccessibilitymac/tst_qaccessibilitymac_helpers.mm
@@ -60,6 +60,43 @@ bool trusted()
return AXIsProcessTrusted();
}
+struct AXErrorTag {
+ AXError err;
+ explicit AXErrorTag(AXError theErr) : err(theErr) {}
+};
+
+QDebug operator<<(QDebug dbg, AXErrorTag err)
+{
+ QDebugStateSaver saver(dbg);
+
+ const char *errDesc = 0;
+ const char *errName = 0;
+ switch (err.err) {
+#define HANDLE_ERR(error, desc) case kAXError##error: errName = "kAXError" #error; errDesc = desc; break
+ HANDLE_ERR(Success, "Success");
+ HANDLE_ERR(Failure, "A system error occurred, such as the failure to allocate an object.");
+ HANDLE_ERR(IllegalArgument, "An illegal argument was passed to the function.");
+ HANDLE_ERR(InvalidUIElement, "The AXUIElementRef passed to the function is invalid.");
+ HANDLE_ERR(InvalidUIElementObserver, "The AXObserverRef passed to the function is not a valid observer.");
+ HANDLE_ERR(CannotComplete, "The function cannot complete because messaging failed in some way or because the application with which the function is communicating is busy or unresponsive.");
+ HANDLE_ERR(AttributeUnsupported, "The attribute is not supported by the AXUIElementRef.");
+ HANDLE_ERR(ActionUnsupported, "The action is not supported by the AXUIElementRef.");
+ HANDLE_ERR(NotificationUnsupported, "The notification is not supported by the AXUIElementRef.");
+ HANDLE_ERR(NotImplemented, "Indicates that the function or method is not implemented (this can be returned if a process does not support the accessibility API).");
+ HANDLE_ERR(NotificationAlreadyRegistered, "This notification has already been registered for.");
+ HANDLE_ERR(NotificationNotRegistered, "Indicates that a notification is not registered yet.");
+ HANDLE_ERR(APIDisabled, "The accessibility API is disabled (as when, for example, the user deselects \"Enable access for assistive devices\" in Universal Access Preferences).");
+ HANDLE_ERR(NoValue, "The requested value or AXUIElementRef does not exist.");
+ HANDLE_ERR(ParameterizedAttributeUnsupported, "The parameterized attribute is not supported by the AXUIElementRef.");
+ HANDLE_ERR(NotEnoughPrecision, "Not enough precision.");
+ default: errName = "<unknown error>"; errDesc = "UNKNOWN ERROR"; break;
+ }
+#undef HANDLE_ERR
+
+ dbg.nospace() << "AXError(value=" << err.err << ", name=" << errName << ", description=\"" << errDesc << "\")";
+
+ return dbg;
+}
#define EXPECT(cond) \
if (!(cond)) { \
@@ -71,41 +108,21 @@ bool trusted()
@interface TestAXObject : NSObject
{
AXUIElementRef reference;
- NSString *_role;
- NSString *_title;
- NSString *_description;
- NSString *_value;
- CGRect _rect;
}
@property (readonly) NSString *role;
@property (readonly) NSString *title;
@property (readonly) NSString *description;
@property (readonly) NSString *value;
@property (readonly) CGRect rect;
+ @property (readonly) NSArray *actions;
@end
@implementation TestAXObject
- @synthesize role = _role;
- @synthesize title = _title;
- @synthesize description = _description;
- @synthesize value = _value;
- @synthesize rect = _rect;
-
- (id) initWithAXUIElementRef: (AXUIElementRef) ref {
if ( self = [super init] ) {
reference = ref;
- AXUIElementCopyAttributeValue(ref, kAXRoleAttribute, (CFTypeRef*)&_role);
- AXUIElementCopyAttributeValue(ref, kAXTitleAttribute, (CFTypeRef*)&_title);
- AXUIElementCopyAttributeValue(ref, kAXDescriptionAttribute, (CFTypeRef*)&_description);
- AXUIElementCopyAttributeValue(ref, kAXValueAttribute, (CFTypeRef*)&_value);
- AXValueRef sizeValue;
- AXUIElementCopyAttributeValue(ref, kAXSizeAttribute, (CFTypeRef*)&sizeValue);
- AXValueGetValue(sizeValue, kAXValueCGSizeType, &_rect.size);
- AXValueRef positionValue;
- AXUIElementCopyAttributeValue(ref, kAXPositionAttribute, (CFTypeRef*)&positionValue);
- AXValueGetValue(positionValue, kAXValueCGPointType, &_rect.origin);
}
return self;
}
@@ -140,24 +157,18 @@ bool trusted()
- (AXUIElementRef) findDirectChildByRole: (CFStringRef) role
{
- AXUIElementRef result = nil;
+ TestAXObject *result = nil;
NSArray *childList = [self childList];
for (id child in childList) {
- CFStringRef typeString;
- AXUIElementCopyAttributeValue((AXUIElementRef)child, kAXRoleAttribute, (CFTypeRef*)&typeString);
- if (CFStringCompare(typeString, role, 0) == 0) {
- result = (AXUIElementRef) child;
+ TestAXObject *childObject = [[TestAXObject alloc] initWithAXUIElementRef:(AXUIElementRef)child];
+ if ([childObject.role isEqualToString:(NSString*)role]) {
+ result = childObject;
break;
}
}
- return result;
-}
-
-- (AXUIElementRef) parent
-{
- AXUIElementRef p = nil;
- AXUIElementCopyAttributeValue(reference, kAXParentAttribute, (CFTypeRef*)&p);
- return p;
+ AXUIElementRef ret = [result ref];
+ [result release];
+ return ret;
}
+ (TestAXObject *) getApplicationAXObject
@@ -168,6 +179,208 @@ bool trusted()
return appObject;
}
++ (NSInteger)_numberFromValue:(CFTypeRef)value
+{
+ NSInteger number = -1;
+ if (!CFNumberGetValue((CFNumberRef)value, kCFNumberNSIntegerType, &number))
+ {
+ qDebug() << "Could not get NSInteger value out of CFNumberRef";
+ }
+ return number;
+}
+
++ (BOOL)_boolFromValue:(CFTypeRef)value
+{
+ return CFBooleanGetValue((CFBooleanRef)value);
+}
+
++ (NSRange)_rangeFromValue:(CFTypeRef)value
+{
+ CFRange cfRange;
+ NSRange range = NSMakeRange(0, 0);
+
+ if (!AXValueGetValue((AXValueRef)value, kAXValueCFRangeType, &cfRange))
+ qDebug() << "Could not get CFRange value out of AXValueRef";
+ else if (cfRange.location < 0 || cfRange.length < 0)
+ qDebug() << "Cannot convert CFRange with negative location or length to NSRange";
+ else if (static_cast<uintmax_t>(cfRange.location) > NSUIntegerMax || static_cast<uintmax_t>(cfRange.length) > NSUIntegerMax)
+ qDebug() << "Cannot convert CFRange with location or length out of bounds for NSUInteger";
+ else
+ {
+ range.length = static_cast<NSUInteger>(cfRange.length);
+ range.location = static_cast<NSUInteger>(cfRange.location);
+ }
+
+ return range;
+}
+
++ (NSRect)_rectFromValue:(CFTypeRef)value
+{
+ NSRect rect = NSMakeRect(0, 0, 0, 0);
+ if (!AXValueGetValue((AXValueRef)value, kAXValueCGRectType, reinterpret_cast<CGRect*>(&rect)))
+ {
+ qDebug() << "Could not get CGRect value out of AXValueRef";
+ }
+ return rect;
+}
+
++ (NSPoint)_pointFromValue:(CFTypeRef)value
+{
+ NSPoint point = NSMakePoint(0, 0);
+ if (!AXValueGetValue((AXValueRef)value, kAXValueCGPointType, reinterpret_cast<CGPoint*>(&point)))
+ {
+ qDebug() << "Could not get CGPoint value out of AXValueRef";
+ }
+ return point;
+}
+
++ (NSSize)_sizeFromValue:(CFTypeRef)value
+{
+ NSSize size = NSMakeSize(0, 0);
+ if (!AXValueGetValue((AXValueRef)value, kAXValueCGSizeType, reinterpret_cast<CGSize*>(&size)))
+ {
+ qDebug() << "Could not get CGSize value out of AXValueRef";
+ }
+ return size;
+}
+
+- (CFTypeRef)_attributeValue:(CFStringRef)attribute
+{
+ CFTypeRef value = NULL;
+ AXError err;
+
+ if (kAXErrorSuccess != (err = AXUIElementCopyAttributeValue(reference, attribute, &value)))
+ {
+ qDebug() << "AXUIElementCopyAttributeValue(" << QString::fromCFString(attribute) << ") returned error = " << AXErrorTag(err);
+ }
+ return value;
+}
+
+- (NSString*)_stringAttributeValue:(CFStringRef)attribute
+{
+ return (NSString*)[self _attributeValue:attribute];
+}
+
+- (NSInteger)_numberAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _numberFromValue:[self _attributeValue:attribute]];
+}
+
+- (BOOL)_boolAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _boolFromValue:[self _attributeValue:attribute]];
+}
+
+- (NSRange)_rangeAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _rangeFromValue:[self _attributeValue:attribute]];
+}
+
+- (NSRect)_rectAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _rectFromValue:[self _attributeValue:attribute]];
+}
+
+- (NSPoint)_pointAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _pointFromValue:[self _attributeValue:attribute]];
+}
+
+- (NSSize)_sizeAttributeValue:(CFStringRef)attribute
+{
+ return [[self class] _sizeFromValue:[self _attributeValue:attribute]];
+}
+
+- (CFTypeRef)_attributeValue:(CFStringRef)attribute forParameter:(CFTypeRef)parameter
+{
+ CFTypeRef value = NULL;
+ AXError err;
+
+ if (kAXErrorSuccess != (err = AXUIElementCopyParameterizedAttributeValue(reference, attribute, parameter, &value)))
+ {
+ CFStringRef description = CFCopyDescription(parameter);
+ qDebug() << "AXUIElementCopyParameterizedAttributeValue(" << QString::fromCFString(attribute) << ", parameter=" << QString::fromCFString(description) << ") returned error = " << AXErrorTag(err);
+ CFRelease(description);
+ }
+ return value;
+}
+
+- (CFTypeRef)_attributeValue:(CFStringRef)attribute forRange:(NSRange)aRange
+{
+ CFRange cfRange = CFRangeMake(aRange.location, aRange.length);
+ AXValueRef range = AXValueCreate(kAXValueCFRangeType, &cfRange);
+ CFTypeRef value = [self _attributeValue:attribute forParameter:range];
+ CFRelease(range);
+ return value;
+}
+
+- (CFTypeRef)_attributeValue:(CFStringRef)attribute forNumber:(NSInteger)aNumber
+{
+ CFNumberRef number = CFNumberCreate(NULL, kCFNumberNSIntegerType, &aNumber);
+ CFTypeRef value = [self _attributeValue:attribute forParameter:number];
+ CFRelease(number);
+ return value;
+}
+
+- (CFTypeRef)_attributeValue:(CFStringRef)attribute forPoint:(CGPoint)aPoint
+{
+ AXValueRef point = AXValueCreate(kAXValueCGPointType, &aPoint);
+ CFTypeRef value = [self _attributeValue:attribute forParameter:point];
+ CFRelease(point);
+ return value;
+}
+
+- (NSArray*)actions
+{
+ AXError err;
+ CFArrayRef actions;
+
+ if (kAXErrorSuccess != (err = AXUIElementCopyActionNames(reference, &actions)))
+ {
+ qDebug() << "AXUIElementCopyActionNames(...) returned error = " << AXErrorTag(err);
+ }
+
+ return (NSArray*)actions;
+}
+
+- (void)performAction:(CFStringRef)action
+{
+ AXError err;
+
+ if (kAXErrorSuccess != (err = AXUIElementPerformAction(reference, action)))
+ {
+ qDebug() << "AXUIElementPerformAction(" << QString::fromCFString(action) << ") returned error = " << AXErrorTag(err);
+ }
+}
+
+- (NSString*) role { return [self _stringAttributeValue:kAXRoleAttribute]; }
+- (NSString*) title { return [self _stringAttributeValue:kAXTitleAttribute]; }
+- (NSString*) description { return [self _stringAttributeValue:kAXDescriptionAttribute]; }
+- (NSString*) value { return [self _stringAttributeValue:kAXValueAttribute]; }
+- (NSInteger) valueNumber { return [self _numberAttributeValue:kAXValueAttribute]; }
+- (NSRect) rect
+{
+ NSRect rect;
+ rect.origin = [self _pointAttributeValue:kAXPositionAttribute];
+ rect.size = [self _sizeAttributeValue:kAXSizeAttribute];
+ return rect;
+}
+- (AXUIElementRef) parent { return (AXUIElementRef)[self _attributeValue:kAXParentAttribute]; }
+- (BOOL) focused { return [self _boolAttributeValue:kAXFocusedAttribute]; }
+- (NSInteger) numberOfCharacters { return [self _numberAttributeValue:kAXNumberOfCharactersAttribute]; }
+- (NSString*) selectedText { return [self _stringAttributeValue:kAXSelectedTextAttribute]; }
+- (NSRange) selectedTextRange { return [self _rangeAttributeValue:kAXSelectedTextRangeAttribute]; }
+- (NSRange) visibleCharacterRange { return [self _rangeAttributeValue:kAXVisibleCharacterRangeAttribute]; }
+- (NSString*) help { return [self _stringAttributeValue:kAXHelpAttribute]; }
+- (NSInteger) insertionPointLineNumber { return [self _numberAttributeValue:kAXInsertionPointLineNumberAttribute]; }
+
+- (NSInteger) lineForIndex:(NSInteger)index { return [[self class] _numberFromValue:[self _attributeValue:kAXLineForIndexParameterizedAttribute forNumber:index]]; }
+- (NSRange) rangeForLine:(NSInteger)line { return [[self class] _rangeFromValue:[self _attributeValue:kAXRangeForLineParameterizedAttribute forNumber:line]]; }
+- (NSString*) stringForRange:(NSRange)range { return (NSString*)[self _attributeValue:kAXStringForRangeParameterizedAttribute forRange:range]; }
+- (NSAttributedString*) attributedStringForRange:(NSRange)range { return (NSAttributedString*)[self _attributeValue:kAXAttributedStringForRangeParameterizedAttribute forRange:range]; }
+- (NSRect) boundsForRange:(NSRange)range { return [[self class] _rectFromValue:[self _attributeValue:kAXBoundsForRangeParameterizedAttribute forRange:range]]; }
+- (NSRange) styleRangeForIndex:(NSInteger)index { return [[self class] _rangeFromValue:[self _attributeValue:kAXStyleRangeForIndexParameterizedAttribute forNumber:index]]; }
+
@end
@@ -225,16 +438,34 @@ bool testLineEdit()
// height of window includes title bar
EXPECT([window rect].size.height >= 400);
- NSString *windowTitle;
- AXUIElementCopyAttributeValue(windowRef, kAXTitleAttribute, (CFTypeRef*)&windowTitle);
- EXPECT([windowTitle isEqualToString:@"Test window"]);
+ EXPECT([window.title isEqualToString:@"Test window"]);
// children of window:
AXUIElementRef lineEdit = [window findDirectChildByRole: kAXTextFieldRole];
EXPECT(lineEdit != nil);
TestAXObject *le = [[TestAXObject alloc] initWithAXUIElementRef: lineEdit];
- EXPECT([[le value] isEqualToString:@"a11y test QLineEdit"]);
+ NSString *value = @"a11y test QLineEdit";
+ EXPECT([le.value isEqualToString:value]);
+ EXPECT(value.length <= NSIntegerMax);
+ EXPECT(le.numberOfCharacters == static_cast<NSInteger>(value.length));
+ const NSRange ranges[] = {
+ { 0, 0},
+ { 0, 1},
+ { 0, 5},
+ { 5, 0},
+ { 5, 1},
+ { 0, value.length},
+ { value.length, 0},
+ };
+ for (size_t i = 0; i < sizeof(ranges)/sizeof(ranges[0]); ++i) {
+ NSRange range = ranges[i];
+ NSString *expectedSubstring = [value substringWithRange:range];
+ NSString *actualSubstring = [le stringForRange:range];
+ NSString *actualAttributedSubstring = [le attributedStringForRange:range].string;
+ EXPECT([actualSubstring isEqualTo:expectedSubstring]);
+ EXPECT([actualAttributedSubstring isEqualTo:expectedSubstring]);
+ }
return true;
}
@@ -357,3 +588,37 @@ bool notifications(QWidget *w)
return true;
}
+
+bool testCheckBox()
+{
+ TestAXObject *appObject = [TestAXObject getApplicationAXObject];
+ EXPECT(appObject);
+
+ NSArray *windowList = [appObject windowList];
+ // one window
+ EXPECT([windowList count] == 1);
+ AXUIElementRef windowRef = (AXUIElementRef) [windowList objectAtIndex: 0];
+ EXPECT(windowRef != nil);
+ TestAXObject *window = [[TestAXObject alloc] initWithAXUIElementRef: windowRef];
+
+ // children of window:
+ AXUIElementRef checkBox = [window findDirectChildByRole: kAXCheckBoxRole];
+ EXPECT(checkBox != nil);
+
+ TestAXObject *cb = [[TestAXObject alloc] initWithAXUIElementRef: checkBox];
+
+ // here start actual checkbox tests
+ EXPECT([cb valueNumber] == 0);
+ EXPECT([cb.title isEqualToString:@"Great option"]);
+ // EXPECT(cb.description == nil); // currently returns "" instead of nil
+
+ EXPECT([cb.actions containsObject:(NSString*)kAXPressAction]);
+
+ [cb performAction:kAXPressAction];
+ EXPECT([cb valueNumber] == 1);
+
+ [cb performAction:kAXPressAction];
+ EXPECT([cb valueNumber] == 0);
+
+ return true;
+}
diff --git a/tests/benchmarks/corelib/tools/qringbuffer/main.cpp b/tests/benchmarks/corelib/tools/qringbuffer/main.cpp
index 6bb82a8056..cf55aeaee5 100644
--- a/tests/benchmarks/corelib/tools/qringbuffer/main.cpp
+++ b/tests/benchmarks/corelib/tools/qringbuffer/main.cpp
@@ -48,10 +48,10 @@ void tst_qringbuffer::reserveAndRead()
{
QRingBuffer ringBuffer;
QBENCHMARK {
- for (int i = 1; i < 256; ++i)
+ for (qint64 i = 1; i < 256; ++i)
ringBuffer.reserve(i);
- for (int i = 1; i < 256; ++i)
+ for (qint64 i = 1; i < 256; ++i)
ringBuffer.read(0, i);
}
}
diff --git a/tests/manual/qscreen/propertywatcher.cpp b/tests/manual/qscreen/propertywatcher.cpp
index cfb5ea272d..19668a8d26 100644
--- a/tests/manual/qscreen/propertywatcher.cpp
+++ b/tests/manual/qscreen/propertywatcher.cpp
@@ -50,6 +50,8 @@ PropertyWatcher::PropertyWatcher(QObject *subject, QString annotation, QWidget *
if (prop.isReadable()) {
PropertyField* field = new PropertyField(m_subject, prop);
m_layout->addRow(prop.name(), field);
+ if (!qstrcmp(prop.name(), "name"))
+ setWindowIconText(prop.read(subject).toString());
}
}
QPushButton *updateButton = new QPushButton("update");