summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
-rwxr-xr-x[-rw-r--r--]src/corelib/tools/qalgorithms.h125
-rwxr-xr-x[-rw-r--r--]src/corelib/tools/qalgorithms.qdoc70
-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/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/qcocoaapplicationdelegate.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm5
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenubar.mm18
-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/haiku/qhaikuclipboard.cpp45
-rw-r--r--src/plugins/platforms/haiku/qhaikuclipboard.h4
-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.cpp65
-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.cpp3
-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/qlayout.cpp3
-rw-r--r--src/widgets/kernel/qwidget.cpp93
-rw-r--r--src/widgets/kernel/qwidget.h9
-rw-r--r--src/widgets/kernel/qwidgetwindow.cpp4
-rw-r--r--src/widgets/util/qsystemtrayicon_x11.cpp32
98 files changed, 2466 insertions, 570 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index ac2f72d573..3006c75794 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 59bd32e9a4..9391799624 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 22c0f03afc..097f641d19 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:
@@ -2259,4 +2268,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/qalgorithms.h b/src/corelib/tools/qalgorithms.h
index ff4d5a3ebd..57fbdf0eba 100644..100755
--- a/src/corelib/tools/qalgorithms.h
+++ b/src/corelib/tools/qalgorithms.h
@@ -584,6 +584,131 @@ Q_DECL_CONST_FUNCTION Q_DECL_CONSTEXPR inline uint qPopulationCount(long unsigne
#undef QALGORITHMS_USE_BUILTIN_POPCOUNT
#endif
+Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint32 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_ctz(v) : 32U;
+#else
+ // see http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightParallel
+ unsigned int c = 32; // c will be the number of zero bits on the right
+ v &= -signed(v);
+ if (v) c--;
+ if (v & 0x0000FFFF) c -= 16;
+ if (v & 0x00FF00FF) c -= 8;
+ if (v & 0x0F0F0F0F) c -= 4;
+ if (v & 0x33333333) c -= 2;
+ if (v & 0x55555555) c -= 1;
+ return c;
+#endif
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_ctz(v) : 8U;
+#else
+ unsigned int c = 8; // c will be the number of zero bits on the right
+ v &= -signed(v);
+ if (v) c--;
+ if (v & 0x0000000F) c -= 4;
+ if (v & 0x00000033) c -= 2;
+ if (v & 0x00000055) c -= 1;
+ return c;
+#endif
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_ctz(v) : 16U;
+#else
+ unsigned int c = 16; // c will be the number of zero bits on the right
+ v &= -signed(v);
+ if (v) c--;
+ if (v & 0x000000FF) c -= 8;
+ if (v & 0x00000F0F) c -= 4;
+ if (v & 0x00003333) c -= 2;
+ if (v & 0x00005555) c -= 1;
+ return c;
+#endif
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint64 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_ctzll(v) : 64;
+#else
+ quint32 x = static_cast<quint32>(v);
+ return x ? qCountTrailingZeroBits(x)
+ : 32 + qCountTrailingZeroBits(static_cast<quint32>(v >> 32));
+#endif
+}
+
+Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(unsigned long v) Q_DECL_NOTHROW
+{
+ return qCountTrailingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
+}
+
+Q_DECL_CONSTEXPR inline uint qCountLeadingZeroBits(quint32 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_clz(v) : 32U;
+#else
+ // Hacker's Delight, 2nd ed. Fig 5-16, p. 102
+ v = v | (v >> 1);
+ v = v | (v >> 2);
+ v = v | (v >> 4);
+ v = v | (v >> 8);
+ v = v | (v >> 16);
+ return qPopulationCount(~v);
+#endif
+}
+
+Q_DECL_CONSTEXPR inline uint qCountLeadingZeroBits(quint8 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_clz(v)-24U : 8U;
+#else
+ v = v | (v >> 1);
+ v = v | (v >> 2);
+ v = v | (v >> 4);
+ return qPopulationCount(static_cast<quint8>(~v));
+#endif
+}
+
+Q_DECL_CONSTEXPR inline uint qCountLeadingZeroBits(quint16 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_clz(v)-16U : 16U;
+#else
+ v = v | (v >> 1);
+ v = v | (v >> 2);
+ v = v | (v >> 4);
+ v = v | (v >> 8);
+ return qPopulationCount(static_cast<quint16>(~v));
+#endif
+}
+
+Q_DECL_CONSTEXPR inline uint qCountLeadingZeroBits(quint64 v) Q_DECL_NOTHROW
+{
+#if defined(Q_CC_GNU)
+ return v ? __builtin_clzll(v) : 64U;
+#else
+ v = v | (v >> 1);
+ v = v | (v >> 2);
+ v = v | (v >> 4);
+ v = v | (v >> 8);
+ v = v | (v >> 16);
+ v = v | (v >> 32);
+ return qPopulationCount(~v);
+#endif
+}
+
+Q_DECL_CONSTEXPR inline uint qCountLeadingZeroBits(unsigned long v) Q_DECL_NOTHROW
+{
+ return qCountLeadingZeroBits(QIntegerForSizeof<long>::Unsigned(v));
+}
+
QT_WARNING_POP
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc
index 193042e017..dac353fa70 100644..100755
--- a/src/corelib/tools/qalgorithms.qdoc
+++ b/src/corelib/tools/qalgorithms.qdoc
@@ -785,3 +785,73 @@
\since 5.2
\overload
*/
+
+/*!
+ \fn uint qCountTrailingZeroBits(quint8 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+
+ Returns the number of consecutive zero bits in \a v, when searching from the LSB.
+ For example, qCountTrailingZeroBits(1) returns 0 and qCountTrailingZeroBits(8) returns 3.
+ */
+
+/*!
+ \fn uint qCountTrailingZeroBits(quint16 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+ \overload
+ */
+
+/*!
+ \fn uint qCountTrailingZeroBits(quint32 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+ \overload
+ */
+
+/*!
+ \fn uint qCountTrailingZeroBits(quint64 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+ \overload
+ */
+
+/*!
+ \fn uint qCountLeadingZeroBits(quint8 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+
+ Returns the number of consecutive zero bits in \a v, when searching from the MSB.
+ For example, qCountLeadingZeroBits(quint8(1)) returns 7 and
+ qCountLeadingZeroBits(quint8(8)) returns 4.
+ */
+
+/*!
+ \fn uint qCountLeadingZeroBits(quint16 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+
+ Returns the number of consecutive zero bits in \a v, when searching from the MSB.
+ For example, qCountLeadingZeroBits(quint16(1)) returns 15 and
+ qCountLeadingZeroBits(quint16(8)) returns 12.
+ */
+
+/*!
+ \fn uint qCountLeadingZeroBits(quint32 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+
+ Returns the number of consecutive zero bits in \a v, when searching from the MSB.
+ For example, qCountLeadingZeroBits(quint32(1)) returns 31 and
+ qCountLeadingZeroBits(quint32(8)) returns 28.
+ */
+
+/*!
+ \fn uint qCountLeadingZeroBits(quint64 v)
+ \relates <QtAlgorithms>
+ \since 5.6
+
+ Returns the number of consecutive zero bits in \a v, when searching from the MSB.
+ For example, qCountLeadingZeroBits(quint64(1)) returns 63 and
+ qCountLeadingZeroBits(quint64(8)) returns 60.
+ */
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 9eac1ed933..6269d9ece3 100644
--- a/src/dbus/qdbusintegrator.cpp
+++ b/src/dbus/qdbusintegrator.cpp
@@ -1889,7 +1889,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 b92e7f5cd7..302d94696d 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 b17978cb7d..ee3fc1589f 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 a6b44cde15..b33d7a74fc 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/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/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 04e51d5392..abaaba91a5 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -100,6 +100,7 @@
- (void)setReflectionDelegate:(NSObject <NSApplicationDelegate> *)oldDelegate;
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent;
- (void) removeAppleEventHandlers;
+- (bool) inLaunch;
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QCocoaApplicationDelegate);
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
index f3a0216870..67d9de859f 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.mm
@@ -284,6 +284,11 @@ QT_END_NAMESPACE
[eventManager removeEventHandlerForEventClass:kInternetEventClass andEventID:kAEGetURL];
}
+- (bool) inLaunch
+{
+ return inLaunch;
+}
+
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
Q_UNUSED(aNotification);
diff --git a/src/plugins/platforms/cocoa/qcocoamenubar.mm b/src/plugins/platforms/cocoa/qcocoamenubar.mm
index 764a01370d..7c902a0e53 100644
--- a/src/plugins/platforms/cocoa/qcocoamenubar.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenubar.mm
@@ -38,6 +38,7 @@
#include "qcocoamenuloader.h"
#include "qcocoaapplication.h" // for custom application category
#include "qcocoaautoreleasepool.h"
+#include "qcocoaapplicationdelegate.h"
#include <QtGui/QGuiApplication>
#include <QtCore/QDebug>
@@ -265,8 +266,21 @@ void QCocoaMenuBar::updateMenuBarImmediately()
QCocoaWindow *cw = findWindowForMenubar();
QWindow *win = cw ? cw->window() : 0;
- if (win && (win->flags() & Qt::Popup) == Qt::Popup)
- return; // context menus, comboboxes, etc. don't need to update the menubar
+ if (win && (win->flags() & Qt::Popup) == Qt::Popup) {
+ // context menus, comboboxes, etc. don't need to update the menubar,
+ // but if an application has only Qt::Tool window(s) on start,
+ // we still have to update the menubar.
+ if ((win->flags() & Qt::WindowType_Mask) != Qt::Tool)
+ return;
+ typedef QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) AppDelegate;
+ NSApplication *app = [NSApplication sharedApplication];
+ if (![app.delegate isKindOfClass:[AppDelegate class]])
+ return;
+ // We apply this logic _only_ during the startup.
+ AppDelegate *appDelegate = app.delegate;
+ if (!appDelegate.inLaunch)
+ return;
+ }
if (cw && cw->menubar())
mb = cw->menubar();
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/haiku/qhaikuclipboard.cpp b/src/plugins/platforms/haiku/qhaikuclipboard.cpp
index f3aa9dc36e..a2d7e96d71 100644
--- a/src/plugins/platforms/haiku/qhaikuclipboard.cpp
+++ b/src/plugins/platforms/haiku/qhaikuclipboard.cpp
@@ -41,6 +41,8 @@
#include <Clipboard.h>
QHaikuClipboard::QHaikuClipboard()
+ : m_systemMimeData(Q_NULLPTR)
+ , m_userMimeData(Q_NULLPTR)
{
if (be_clipboard)
be_clipboard->StartWatching(BMessenger(this));
@@ -50,17 +52,26 @@ QHaikuClipboard::~QHaikuClipboard()
{
if (be_clipboard)
be_clipboard->StopWatching(BMessenger(this));
+
+ delete m_userMimeData;
+ delete m_systemMimeData;
}
QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode)
{
- QMimeData *mimeData = new QMimeData();
-
if (mode != QClipboard::Clipboard)
- return mimeData;
+ return 0;
+
+ if (m_userMimeData)
+ return m_userMimeData;
if (!be_clipboard->Lock())
- return mimeData;
+ return 0;
+
+ if (!m_systemMimeData)
+ m_systemMimeData = new QMimeData();
+ else
+ m_systemMimeData->clear();
const BMessage *clipboard = be_clipboard->Data();
if (clipboard) {
@@ -76,11 +87,11 @@ QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode)
if (dataLen && (status == B_OK)) {
const QString format = QString::fromLatin1(name);
if (format == QStringLiteral("text/plain")) {
- mimeData->setText(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
+ m_systemMimeData->setText(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
} else if (format == QStringLiteral("text/html")) {
- mimeData->setHtml(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
+ m_systemMimeData->setHtml(QString::fromLocal8Bit(reinterpret_cast<const char*>(data), dataLen));
} else {
- mimeData->setData(format, QByteArray(reinterpret_cast<const char*>(data), dataLen));
+ m_systemMimeData->setData(format, QByteArray(reinterpret_cast<const char*>(data), dataLen));
}
}
}
@@ -88,7 +99,7 @@ QMimeData *QHaikuClipboard::mimeData(QClipboard::Mode mode)
be_clipboard->Unlock();
- return mimeData;
+ return m_systemMimeData;
}
void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
@@ -96,6 +107,14 @@ void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
if (mode != QClipboard::Clipboard)
return;
+ if (mimeData) {
+ if (m_systemMimeData == mimeData)
+ return;
+
+ if (m_userMimeData == mimeData)
+ return;
+ }
+
if (!be_clipboard->Lock())
return;
@@ -115,6 +134,10 @@ void QHaikuClipboard::setMimeData(QMimeData *mimeData, QClipboard::Mode mode)
qWarning("Unable to store mime data on clipboard");
be_clipboard->Unlock();
+
+ m_userMimeData = mimeData;
+
+ emitChanged(QClipboard::Clipboard);
}
bool QHaikuClipboard::supportsMode(QClipboard::Mode mode) const
@@ -131,8 +154,12 @@ bool QHaikuClipboard::ownsMode(QClipboard::Mode mode) const
void QHaikuClipboard::MessageReceived(BMessage* message)
{
- if (message->what == B_CLIPBOARD_CHANGED)
+ if (message->what == B_CLIPBOARD_CHANGED) {
+ delete m_userMimeData;
+ m_userMimeData = Q_NULLPTR;
+
emitChanged(QClipboard::Clipboard);
+ }
BHandler::MessageReceived(message);
}
diff --git a/src/plugins/platforms/haiku/qhaikuclipboard.h b/src/plugins/platforms/haiku/qhaikuclipboard.h
index 0dc2bfdd3b..3c1f92c615 100644
--- a/src/plugins/platforms/haiku/qhaikuclipboard.h
+++ b/src/plugins/platforms/haiku/qhaikuclipboard.h
@@ -55,6 +55,10 @@ public:
// override from BHandler to catch change notifications from Haiku clipboard
void MessageReceived(BMessage* message) Q_DECL_OVERRIDE;
+
+private:
+ QMimeData *m_systemMimeData;
+ QMimeData *m_userMimeData;
};
QT_END_NAMESPACE
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 f4c633e2d7..706b9c8e48 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1974,10 +1974,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*)));
}
@@ -1985,6 +1986,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 f479c1bc80..1190e7c2b0 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -465,7 +465,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 *);
@@ -476,6 +478,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 34179a70a4..0b38def63b 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>
@@ -1475,10 +1476,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()) {
@@ -1643,6 +1656,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);
@@ -1759,6 +1778,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 c08408a1ca..2442e6c4e3 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;
@@ -143,6 +144,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 fcdc6c32e0..9dad394a06 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -110,7 +110,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 cd115bdcae..52a9977bbf 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 <QtCore/QSysInfo>
#include <set>
@@ -60,74 +63,78 @@ 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;
- }
QByteArray distributionName = QSysInfo::productType().toLower().toUtf8();
QByteArray distributionRelease = QSysInfo::productVersion().toLower().toUtf8();
if (!distributionName.isEmpty()) {
- if (matches.find(distributionName) == matches.end())
- matches.insert(distributionName);
- matches.insert(distributionName + "-" + distributionRelease);
+ if (matchedConditions.find(distributionName) == matchedConditions.end())
+ matchedConditions.insert(distributionName);
+ matchedConditions.insert(distributionName + "-" + distributionRelease);
}
for (int i = 0; i < conds.size(); ++i) {
@@ -136,7 +143,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 0b156c6bb9..a521daadbb 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 a2bf14b25b..c598a5b4cb 100644
--- a/src/widgets/accessible/qaccessiblewidgets.cpp
+++ b/src/widgets/accessible/qaccessiblewidgets.cpp
@@ -826,6 +826,9 @@ QString QAccessibleTextWidget::attributes(int offset, int *startOffset, int *end
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/qlayout.cpp b/src/widgets/kernel/qlayout.cpp
index 822690942e..dcacea4777 100644
--- a/src/widgets/kernel/qlayout.cpp
+++ b/src/widgets/kernel/qlayout.cpp
@@ -1175,13 +1175,12 @@ QLayoutItem *QLayout::replaceWidget(QWidget *from, QWidget *to, Qt::FindChildOpt
if (index == -1)
return 0;
+ addChildWidget(to);
QLayoutItem *newitem = new QWidgetItem(to);
newitem->setAlignment(item->alignment());
QLayoutItem *r = d->replaceAt(index, newitem);
if (!r)
delete newitem;
- else
- addChildWidget(to);
return r;
}
diff --git a/src/widgets/kernel/qwidget.cpp b/src/widgets/kernel/qwidget.cpp
index e1053b4add..a48bfdf3c6 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
{
@@ -6108,8 +6116,15 @@ QIcon QWidget::windowIcon() const
void QWidgetPrivate::setWindowIcon_helper()
{
+ Q_Q(QWidget);
QEvent e(QEvent::WindowIconChange);
- QApplication::sendEvent(q_func(), &e);
+
+ // Do not send the event if the widget is a top level.
+ // In that case, setWindowIcon_sys does it, and event propagation from
+ // QWidgetWindow to the top level QWidget ensures that the event reaches
+ // the top level anyhow
+ if (!q->windowHandle())
+ QApplication::sendEvent(q, &e);
for (int i = 0; i < children.size(); ++i) {
QWidget *w = qobject_cast<QWidget *>(children.at(i));
if (w && !w->isWindow())
@@ -6152,10 +6167,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 +12829,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/kernel/qwidgetwindow.cpp b/src/widgets/kernel/qwidgetwindow.cpp
index ba8c16e838..efe7d9415b 100644
--- a/src/widgets/kernel/qwidgetwindow.cpp
+++ b/src/widgets/kernel/qwidgetwindow.cpp
@@ -161,7 +161,7 @@ bool QWidgetWindow::event(QEvent *event)
if (m_widget->testAttribute(Qt::WA_DontShowOnScreen)) {
// \a event is uninteresting for QWidgetWindow, the event was probably
// generated before WA_DontShowOnScreen was set
- return m_widget->event(event);
+ return QCoreApplication::sendEvent(m_widget, event);
}
switch (event->type()) {
@@ -303,7 +303,7 @@ bool QWidgetWindow::event(QEvent *event)
break;
}
- if (m_widget->event(event) && event->type() != QEvent::Timer)
+ if (QCoreApplication::sendEvent(m_widget, event) && event->type() != QEvent::Timer)
return true;
return QWindow::event(event);
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)