Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I6f8d3abd3247dc980dc7834801a017a89c8f4286
This commit is contained in:
commit
f09fc1f352
4
src/3rdparty/angle/qt_attribution.json
vendored
4
src/3rdparty/angle/qt_attribution.json
vendored
@ -5,6 +5,10 @@
|
||||
"QDocModule": "qtgui",
|
||||
"QtUsage": "Used on Windows to implement OpenGL ES on top of DirectX. Configure with -no-opengl, or -opengl desktop to exclude.",
|
||||
|
||||
"Description": "The ANGLE library translates OpenGL ES API calls to hardware-supported APIs.",
|
||||
"Homepage": "http://angleproject.org/",
|
||||
"Version": "chromium/3280",
|
||||
|
||||
"License": "BSD 3-clause \"New\" or \"Revised\" License",
|
||||
"LicenseId": "BSD-3-Clause",
|
||||
"LicenseFile": "LICENSE",
|
||||
|
@ -41,6 +41,7 @@
|
||||
#ifndef QENDIAN_H
|
||||
#define QENDIAN_H
|
||||
|
||||
#include <QtCore/qfloat16.h>
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
// include stdlib.h and hope that it defines __GLIBC__ for glibc-based systems
|
||||
@ -151,6 +152,31 @@ template <> inline Q_DECL_CONSTEXPR qint8 qbswap<qint8>(qint8 source)
|
||||
return source;
|
||||
}
|
||||
|
||||
// floating specializations
|
||||
template<typename Float>
|
||||
Float qbswapFloatHelper(Float source)
|
||||
{
|
||||
// memcpy call in qFromUnaligned is recognized by optimizer as a correct way of type prunning
|
||||
auto temp = qFromUnaligned<typename QIntegerForSizeof<Float>::Unsigned>(&source);
|
||||
temp = qbswap(temp);
|
||||
return qFromUnaligned<Float>(&temp);
|
||||
}
|
||||
|
||||
template <> inline qfloat16 qbswap<qfloat16>(qfloat16 source)
|
||||
{
|
||||
return qbswapFloatHelper(source);
|
||||
}
|
||||
|
||||
template <> inline float qbswap<float>(float source)
|
||||
{
|
||||
return qbswapFloatHelper(source);
|
||||
}
|
||||
|
||||
template <> inline double qbswap<double>(double source)
|
||||
{
|
||||
return qbswapFloatHelper(source);
|
||||
}
|
||||
|
||||
/*
|
||||
* qbswap(const T src, const void *dest);
|
||||
* Changes the byte order of \a src from big endian to little endian or vice versa
|
||||
|
@ -333,7 +333,7 @@ QIODevicePrivate::~QIODevicePrivate()
|
||||
allowed. This flag currently only affects QFile. Other
|
||||
classes might use this flag in the future, but until then
|
||||
using this flag with any classes other than QFile may
|
||||
result in undefined behavior.
|
||||
result in undefined behavior. (since Qt 5.11)
|
||||
\value ExistingOnly Fail if the file to be opened does not exist. This flag
|
||||
must be specified alongside ReadOnly, WriteOnly, or
|
||||
ReadWrite. Note that using this flag with ReadOnly alone
|
||||
@ -341,7 +341,7 @@ QIODevicePrivate::~QIODevicePrivate()
|
||||
not exist. This flag currently only affects QFile. Other
|
||||
classes might use this flag in the future, but until then
|
||||
using this flag with any classes other than QFile may
|
||||
result in undefined behavior.
|
||||
result in undefined behavior. (since Qt 5.11)
|
||||
|
||||
Certain flags, such as \c Unbuffered and \c Truncate, are
|
||||
meaningless when used with some subclasses. Some of these
|
||||
|
@ -417,6 +417,23 @@ static const char *findWMstr(uint msg)
|
||||
{ 0x0232, "WM_EXITSIZEMOVE" },
|
||||
{ 0x0233, "WM_DROPFILES" },
|
||||
{ 0x0234, "WM_MDIREFRESHMENU" },
|
||||
{ 0x0241, "WM_NCPOINTERUPDATE"},
|
||||
{ 0x0242, "WM_NCPOINTERDOWN"},
|
||||
{ 0x0243, "WM_NCPOINTERUP"},
|
||||
{ 0x0245, "WM_POINTERUPDATE"},
|
||||
{ 0x0246, "WM_POINTERDOWN"},
|
||||
{ 0x0247, "WM_POINTERUP"},
|
||||
{ 0x0249, "WM_POINTERENTER"},
|
||||
{ 0x024A, "WM_POINTERLEAVE"},
|
||||
{ 0x0248, "WM_POINTERACTIVATE"},
|
||||
{ 0x024C, "WM_POINTERCAPTURECHANGED"},
|
||||
{ 0x024D, "WM_TOUCHHITTESTING"},
|
||||
{ 0x024E, "WM_POINTERWHEEL"},
|
||||
{ 0x024F, "WM_POINTERHWHEEL"},
|
||||
{ 0x0250, "DM_POINTERHITTEST"},
|
||||
{ 0x0251, "WM_POINTERROUTEDTO"},
|
||||
{ 0x0252, "WM_POINTERROUTEDAWAY"},
|
||||
{ 0x0253, "WM_POINTERROUTEDRELEASED"},
|
||||
{ 0x0281, "WM_IME_SETCONTEXT" },
|
||||
{ 0x0282, "WM_IME_NOTIFY" },
|
||||
{ 0x0283, "WM_IME_CONTROL" },
|
||||
|
@ -421,6 +421,7 @@ void QObjectPrivate::cleanConnectionLists()
|
||||
{
|
||||
if (connectionLists->dirty && !connectionLists->inUse) {
|
||||
// remove broken connections
|
||||
bool allConnected = false;
|
||||
for (int signal = -1; signal < connectionLists->count(); ++signal) {
|
||||
QObjectPrivate::ConnectionList &connectionList =
|
||||
(*connectionLists)[signal];
|
||||
@ -432,11 +433,13 @@ void QObjectPrivate::cleanConnectionLists()
|
||||
|
||||
QObjectPrivate::Connection **prev = &connectionList.first;
|
||||
QObjectPrivate::Connection *c = *prev;
|
||||
bool connected = false; // whether the signal is still connected somewhere
|
||||
while (c) {
|
||||
if (c->receiver) {
|
||||
last = c;
|
||||
prev = &c->nextConnectionList;
|
||||
c = *prev;
|
||||
connected = true;
|
||||
} else {
|
||||
QObjectPrivate::Connection *next = c->nextConnectionList;
|
||||
*prev = next;
|
||||
@ -448,6 +451,14 @@ void QObjectPrivate::cleanConnectionLists()
|
||||
// Correct the connection list's last pointer.
|
||||
// As conectionList.last could equal last, this could be a noop
|
||||
connectionList.last = last;
|
||||
|
||||
if (!allConnected && !connected && signal >= 0
|
||||
&& size_t(signal) < sizeof(connectedSignals) * 8) {
|
||||
// This signal is no longer connected
|
||||
connectedSignals[signal >> 5] &= ~(1 << (signal & 0x1f));
|
||||
} else if (signal == -1) {
|
||||
allConnected = connected;
|
||||
}
|
||||
}
|
||||
connectionLists->dirty = false;
|
||||
}
|
||||
@ -2502,19 +2513,20 @@ bool QObject::isSignalConnected(const QMetaMethod &signal) const
|
||||
|
||||
signalIndex += QMetaObjectPrivate::signalOffset(signal.mobj);
|
||||
|
||||
if (signalIndex < sizeof(d->connectedSignals) * 8)
|
||||
QMutexLocker locker(signalSlotLock(this));
|
||||
if (!d->connectionLists)
|
||||
return false;
|
||||
|
||||
if (signalIndex < sizeof(d->connectedSignals) * 8 && !d->connectionLists->dirty)
|
||||
return d->isSignalConnected(signalIndex);
|
||||
|
||||
QMutexLocker locker(signalSlotLock(this));
|
||||
if (d->connectionLists) {
|
||||
if (signalIndex < uint(d->connectionLists->count())) {
|
||||
const QObjectPrivate::Connection *c =
|
||||
d->connectionLists->at(signalIndex).first;
|
||||
while (c) {
|
||||
if (c->receiver)
|
||||
return true;
|
||||
c = c->nextConnectionList;
|
||||
}
|
||||
if (signalIndex < uint(d->connectionLists->count())) {
|
||||
const QObjectPrivate::Connection *c =
|
||||
d->connectionLists->at(signalIndex).first;
|
||||
while (c) {
|
||||
if (c->receiver)
|
||||
return true;
|
||||
c = c->nextConnectionList;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -465,11 +465,7 @@ int QThread::idealThreadCount() Q_DECL_NOTHROW
|
||||
|
||||
void QThread::yieldCurrentThread()
|
||||
{
|
||||
#if !defined(Q_OS_WINRT)
|
||||
SwitchToThread();
|
||||
#else
|
||||
::Sleep(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // QT_CONFIG(thread)
|
||||
|
@ -217,6 +217,7 @@ void QContiguousCache<T>::setCapacity(int asize)
|
||||
detach();
|
||||
union { QContiguousCacheData *d; QContiguousCacheTypedData<T> *p; } x;
|
||||
x.d = allocateData(asize);
|
||||
x.d->ref.store(1);
|
||||
x.d->alloc = asize;
|
||||
x.d->count = qMin(d->count, asize);
|
||||
x.d->offset = d->offset + d->count - x.d->count;
|
||||
|
@ -954,7 +954,18 @@ void QPdfEngine::drawPixmap (const QRectF &rectangle, const QPixmap &pixmap, con
|
||||
if (object < 0)
|
||||
return;
|
||||
|
||||
*d->currentPage << "q\n/GSa gs\n";
|
||||
*d->currentPage << "q\n";
|
||||
|
||||
if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) {
|
||||
int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity));
|
||||
if (stateObject)
|
||||
*d->currentPage << "/GState" << stateObject << "gs\n";
|
||||
else
|
||||
*d->currentPage << "/GSa gs\n";
|
||||
} else {
|
||||
*d->currentPage << "/GSa gs\n";
|
||||
}
|
||||
|
||||
*d->currentPage
|
||||
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
|
||||
rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
|
||||
@ -983,7 +994,18 @@ void QPdfEngine::drawImage(const QRectF &rectangle, const QImage &image, const Q
|
||||
if (object < 0)
|
||||
return;
|
||||
|
||||
*d->currentPage << "q\n/GSa gs\n";
|
||||
*d->currentPage << "q\n";
|
||||
|
||||
if ((d->pdfVersion != QPdfEngine::Version_A1b) && (d->opacity != 1.0)) {
|
||||
int stateObject = d->addConstantAlphaObject(qRound(255 * d->opacity), qRound(255 * d->opacity));
|
||||
if (stateObject)
|
||||
*d->currentPage << "/GState" << stateObject << "gs\n";
|
||||
else
|
||||
*d->currentPage << "/GSa gs\n";
|
||||
} else {
|
||||
*d->currentPage << "/GSa gs\n";
|
||||
}
|
||||
|
||||
*d->currentPage
|
||||
<< QPdf::generateMatrix(QTransform(rectangle.width() / sr.width(), 0, 0, rectangle.height() / sr.height(),
|
||||
rectangle.x(), rectangle.y()) * (d->simplePen ? QTransform() : d->stroker.matrix));
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
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
|
||||
QRgba64 can be used as a replacement for QRgb when higher precision is needed. In particular a
|
||||
premultiplied QRgba64 can operate on unpremultiplied QRgb without loss of precision except
|
||||
for alpha 0.
|
||||
|
||||
|
@ -86,6 +86,7 @@
|
||||
#include <private/qguiapplication_p.h>
|
||||
#include "qt_mac_p.h"
|
||||
#include <qpa/qwindowsysteminterface.h>
|
||||
#include <qwindowdefs.h>
|
||||
|
||||
QT_USE_NAMESPACE
|
||||
|
||||
@ -93,6 +94,7 @@ QT_USE_NAMESPACE
|
||||
bool startedQuit;
|
||||
NSObject <NSApplicationDelegate> *reflectionDelegate;
|
||||
bool inLaunch;
|
||||
QWindowList hiddenWindows;
|
||||
}
|
||||
|
||||
+ (instancetype)sharedDelegate
|
||||
@ -322,12 +324,28 @@ QT_USE_NAMESPACE
|
||||
// fact that the application itself is hidden, which will cause a problem when
|
||||
// the application is made visible again.
|
||||
const QWindowList topLevelWindows = QGuiApplication::topLevelWindows();
|
||||
for (QWindow *topLevelWindow : qAsConst(topLevelWindows)) {
|
||||
if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible())
|
||||
for (QWindow *topLevelWindow : topLevelWindows) {
|
||||
if ((topLevelWindow->type() & Qt::Popup) == Qt::Popup && topLevelWindow->isVisible()) {
|
||||
topLevelWindow->hide();
|
||||
|
||||
if ((topLevelWindow->type() & Qt::Tool) == Qt::Tool)
|
||||
hiddenWindows << topLevelWindow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applicationDidUnhide:(NSNotification *)notification
|
||||
{
|
||||
if (reflectionDelegate
|
||||
&& [reflectionDelegate respondsToSelector:@selector(applicationDidUnhide:)])
|
||||
[reflectionDelegate applicationDidUnhide:notification];
|
||||
|
||||
for (QWindow *window : qAsConst(hiddenWindows))
|
||||
window->show();
|
||||
|
||||
hiddenWindows.clear();
|
||||
}
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
||||
{
|
||||
if (reflectionDelegate
|
||||
|
@ -546,7 +546,7 @@ int QWasmEventTranslator::touchCallback(int eventType, const EmscriptenTouchEven
|
||||
else
|
||||
QWindowSystemInterface::handleTouchCancelEvent(window2, wasmEventTranslator->getTimestamp(), wasmEventTranslator->touchDevice, keyModifier);
|
||||
|
||||
QCoreApplication::processEvents();
|
||||
QWasmEventDispatcher::maintainTimers();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -484,6 +484,9 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h
|
||||
case WM_POINTERHWHEEL:
|
||||
case WM_POINTERWHEEL: {
|
||||
|
||||
if (!isValidWheelReceiver(window))
|
||||
return true;
|
||||
|
||||
int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
|
||||
|
||||
// Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL
|
||||
@ -493,8 +496,7 @@ bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND h
|
||||
const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ?
|
||||
QPoint(delta, 0) : QPoint(0, delta);
|
||||
|
||||
if (isValidWheelReceiver(window))
|
||||
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
|
||||
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
|
||||
return true;
|
||||
}
|
||||
case WM_POINTERLEAVE:
|
||||
@ -508,7 +510,6 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
|
||||
MSG msg, PVOID vTouchInfo, quint32 count)
|
||||
{
|
||||
Q_UNUSED(hwnd);
|
||||
Q_UNUSED(et);
|
||||
|
||||
if (et & QtWindows::NonClientEventFlag)
|
||||
return false; // Let DefWindowProc() handle Non Client messages.
|
||||
@ -707,21 +708,46 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
|
||||
// Process old-style mouse messages here.
|
||||
bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
|
||||
{
|
||||
Q_UNUSED(et);
|
||||
|
||||
// Generate enqueued events.
|
||||
flushTouchEvents(m_touchDevice);
|
||||
flushTabletEvents();
|
||||
|
||||
*result = 0;
|
||||
if (msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE)
|
||||
if (et != QtWindows::MouseWheelEvent && msg.message != WM_MOUSELEAVE && msg.message != WM_MOUSEMOVE)
|
||||
return false;
|
||||
|
||||
const QPoint localPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
const QPoint globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, localPos);
|
||||
const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
|
||||
QPoint localPos;
|
||||
QPoint globalPos;
|
||||
if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) {
|
||||
globalPos = eventPos;
|
||||
localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
|
||||
} else {
|
||||
localPos = eventPos;
|
||||
globalPos = QWindowsGeometryHint::mapToGlobal(hwnd, eventPos);
|
||||
}
|
||||
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
|
||||
|
||||
if (et == QtWindows::MouseWheelEvent) {
|
||||
|
||||
if (!isValidWheelReceiver(window))
|
||||
return true;
|
||||
|
||||
int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
|
||||
|
||||
// Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL
|
||||
if (msg.message == WM_MOUSEHWHEEL)
|
||||
delta = -delta;
|
||||
|
||||
const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
|
||||
QPoint(delta, 0) : QPoint(0, delta);
|
||||
|
||||
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (msg.message == WM_MOUSELEAVE) {
|
||||
if (window == m_currentWindow) {
|
||||
QWindowSystemInterface::handleLeaveEvent(window);
|
||||
@ -762,7 +788,6 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW
|
||||
m_windowUnderPointer = currentWindowUnderPointer;
|
||||
}
|
||||
|
||||
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
|
||||
const Qt::MouseButtons mouseButtons = queryMouseButtons();
|
||||
|
||||
if (!discardEvent)
|
||||
|
@ -153,114 +153,71 @@ private:
|
||||
QByteArray format_atoms;
|
||||
};
|
||||
|
||||
namespace {
|
||||
class INCRTransaction;
|
||||
typedef QMap<xcb_window_t,INCRTransaction*> TransactionMap;
|
||||
static TransactionMap *transactions = 0;
|
||||
|
||||
//#define INCR_DEBUG
|
||||
|
||||
class INCRTransaction : public QObject
|
||||
QXcbClipboardTransaction::QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w,
|
||||
xcb_atom_t p, QByteArray d, xcb_atom_t t, int f)
|
||||
: m_clipboard(clipboard), m_window(w), m_property(p), m_data(d), m_target(t), m_format(f)
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
INCRTransaction(QXcbConnection *c, xcb_window_t w, xcb_atom_t p,
|
||||
QByteArray d, uint i, xcb_atom_t t, int f, int to) :
|
||||
conn(c), win(w), property(p), data(d), increment(i),
|
||||
target(t), format(f), timeout(to), offset(0)
|
||||
{
|
||||
const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
xcb_change_window_attributes(conn->xcb_connection(), win,
|
||||
const quint32 values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
|
||||
XCB_CW_EVENT_MASK, values);
|
||||
|
||||
m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
|
||||
}
|
||||
|
||||
QXcbClipboardTransaction::~QXcbClipboardTransaction()
|
||||
{
|
||||
if (m_abortTimerId)
|
||||
killTimer(m_abortTimerId);
|
||||
m_abortTimerId = 0;
|
||||
m_clipboard->removeTransaction(m_window);
|
||||
}
|
||||
|
||||
bool QXcbClipboardTransaction::updateIncrementalProperty(const xcb_property_notify_event_t *event)
|
||||
{
|
||||
if (event->atom != m_property || event->state != XCB_PROPERTY_DELETE)
|
||||
return false;
|
||||
|
||||
// restart the timer
|
||||
if (m_abortTimerId)
|
||||
killTimer(m_abortTimerId);
|
||||
m_abortTimerId = startTimer(m_clipboard->clipboardTimeout());
|
||||
|
||||
uint bytes_left = uint(m_data.size()) - m_offset;
|
||||
if (bytes_left > 0) {
|
||||
int increment = m_clipboard->increment();
|
||||
uint bytes_to_send = qMin(uint(increment), bytes_left);
|
||||
|
||||
qCDebug(lcQpaClipboard, "sending %d bytes, %d remaining, transaction: %p)",
|
||||
bytes_to_send, bytes_left - bytes_to_send, this);
|
||||
|
||||
uint32_t dataSize = bytes_to_send / (m_format / 8);
|
||||
xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
|
||||
m_property, m_target, m_format, dataSize, m_data.constData() + m_offset);
|
||||
m_offset += bytes_to_send;
|
||||
} else {
|
||||
qCDebug(lcQpaClipboard, "transaction %p completed", this);
|
||||
|
||||
xcb_change_property(m_clipboard->xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
|
||||
m_property, m_target, m_format, 0, nullptr);
|
||||
|
||||
const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
|
||||
xcb_change_window_attributes(m_clipboard->xcb_connection(), m_window,
|
||||
XCB_CW_EVENT_MASK, values);
|
||||
if (!transactions) {
|
||||
#ifdef INCR_DEBUG
|
||||
qDebug("INCRTransaction: creating the TransactionMap");
|
||||
#endif
|
||||
transactions = new TransactionMap;
|
||||
conn->clipboard()->setProcessIncr(true);
|
||||
}
|
||||
transactions->insert(win, this);
|
||||
abort_timer = startTimer(timeout);
|
||||
delete this; // self destroy
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
~INCRTransaction()
|
||||
{
|
||||
if (abort_timer)
|
||||
killTimer(abort_timer);
|
||||
abort_timer = 0;
|
||||
transactions->remove(win);
|
||||
if (transactions->isEmpty()) {
|
||||
#ifdef INCR_DEBUG
|
||||
qDebug("INCRTransaction: no more INCR transactions left in the TransactionMap");
|
||||
#endif
|
||||
delete transactions;
|
||||
transactions = 0;
|
||||
conn->clipboard()->setProcessIncr(false);
|
||||
}
|
||||
|
||||
void QXcbClipboardTransaction::timerEvent(QTimerEvent *ev)
|
||||
{
|
||||
if (ev->timerId() == m_abortTimerId) {
|
||||
// this can happen when the X client we are sending data
|
||||
// to decides to exit (normally or abnormally)
|
||||
qCDebug(lcQpaClipboard, "timed out while sending data to %p", this);
|
||||
delete this; // self destroy
|
||||
}
|
||||
|
||||
void updateIncrProperty(xcb_property_notify_event_t *event, bool &accepted)
|
||||
{
|
||||
xcb_connection_t *c = conn->xcb_connection();
|
||||
if (event->atom == property && event->state == XCB_PROPERTY_DELETE) {
|
||||
accepted = true;
|
||||
// restart the timer
|
||||
if (abort_timer)
|
||||
killTimer(abort_timer);
|
||||
abort_timer = startTimer(timeout);
|
||||
|
||||
unsigned int bytes_left = data.size() - offset;
|
||||
if (bytes_left > 0) {
|
||||
unsigned int bytes_to_send = qMin(increment, bytes_left);
|
||||
#ifdef INCR_DEBUG
|
||||
qDebug("INCRTransaction: sending %d bytes, %d remaining (INCR transaction %p)",
|
||||
bytes_to_send, bytes_left - bytes_to_send, this);
|
||||
#endif
|
||||
int dataSize = bytes_to_send / (format / 8);
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
|
||||
target, format, dataSize, data.constData() + offset);
|
||||
offset += bytes_to_send;
|
||||
} else {
|
||||
#ifdef INCR_DEBUG
|
||||
qDebug("INCRTransaction: INCR transaction %p completed", this);
|
||||
#endif
|
||||
xcb_change_property(c, XCB_PROP_MODE_REPLACE, win, property,
|
||||
target, format, 0, (const void *)0);
|
||||
const quint32 values[] = { XCB_EVENT_MASK_NO_EVENT };
|
||||
xcb_change_window_attributes(conn->xcb_connection(), win,
|
||||
XCB_CW_EVENT_MASK, values);
|
||||
// self destroy
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *ev) override
|
||||
{
|
||||
if (ev->timerId() == abort_timer) {
|
||||
// this can happen when the X client we are sending data
|
||||
// to decides to exit (normally or abnormally)
|
||||
#ifdef INCR_DEBUG
|
||||
qDebug("INCRTransaction: Timed out while sending data to %p", this);
|
||||
#endif
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QXcbConnection *conn;
|
||||
xcb_window_t win;
|
||||
xcb_atom_t property;
|
||||
QByteArray data;
|
||||
uint increment;
|
||||
xcb_atom_t target;
|
||||
int format;
|
||||
int timeout;
|
||||
uint offset;
|
||||
int abort_timer;
|
||||
};
|
||||
} // unnamed namespace
|
||||
}
|
||||
|
||||
const int QXcbClipboard::clipboard_timeout = 5000;
|
||||
|
||||
@ -282,6 +239,9 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
|
||||
xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask);
|
||||
xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask);
|
||||
}
|
||||
|
||||
// change property protocol request is 24 bytes
|
||||
m_increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
|
||||
}
|
||||
|
||||
QXcbClipboard::~QXcbClipboard()
|
||||
@ -313,16 +273,17 @@ QXcbClipboard::~QXcbClipboard()
|
||||
delete m_clientClipboard[QClipboard::Selection];
|
||||
}
|
||||
|
||||
void QXcbClipboard::incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted)
|
||||
bool QXcbClipboard::handlePropertyNotify(const xcb_generic_event_t *event)
|
||||
{
|
||||
uint response_type = ge->response_type & ~0x80;
|
||||
if (response_type == XCB_PROPERTY_NOTIFY) {
|
||||
xcb_property_notify_event_t *event = (xcb_property_notify_event_t *)ge;
|
||||
TransactionMap::Iterator it = transactions->find(event->window);
|
||||
if (it != transactions->end()) {
|
||||
(*it)->updateIncrProperty(event, accepted);
|
||||
}
|
||||
}
|
||||
if (m_transactions.isEmpty() || event->response_type != XCB_PROPERTY_NOTIFY)
|
||||
return false;
|
||||
|
||||
auto propertyNotify = reinterpret_cast<const xcb_property_notify_event_t *>(event);
|
||||
TransactionMap::Iterator it = m_transactions.find(propertyNotify->window);
|
||||
if (it == m_transactions.constEnd())
|
||||
return false;
|
||||
|
||||
return (*it)->updateIncrementalProperty(propertyNotify);
|
||||
}
|
||||
|
||||
xcb_window_t QXcbClipboard::getSelectionOwner(xcb_atom_t atom) const
|
||||
@ -522,19 +483,18 @@ xcb_atom_t QXcbClipboard::sendSelection(QMimeData *d, xcb_atom_t target, xcb_win
|
||||
// This 'bool' can be removed once there is a proper fix for QTBUG-32853
|
||||
if (m_clipboard_closing)
|
||||
allow_incr = false;
|
||||
// X_ChangeProperty protocol request is 24 bytes
|
||||
const int increment = (xcb_get_maximum_request_length(xcb_connection()) * 4) - 24;
|
||||
if (data.size() > increment && allow_incr) {
|
||||
|
||||
if (data.size() > m_increment && allow_incr) {
|
||||
long bytes = data.size();
|
||||
xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, window, property,
|
||||
atom(QXcbAtom::INCR), 32, 1, (const void *)&bytes);
|
||||
new INCRTransaction(connection(), window, property, data, increment,
|
||||
atomFormat, dataFormat, clipboard_timeout);
|
||||
auto transaction = new QXcbClipboardTransaction(this, window, property, data, atomFormat, dataFormat);
|
||||
m_transactions.insert(window, transaction);
|
||||
return property;
|
||||
}
|
||||
|
||||
// make sure we can perform the XChangeProperty in a single request
|
||||
if (data.size() > increment)
|
||||
if (data.size() > m_increment)
|
||||
return XCB_NONE; // ### perhaps use several XChangeProperty calls w/ PropModeAppend?
|
||||
int dataSize = data.size() / (dataFormat / 8);
|
||||
// use a single request to transfer data
|
||||
|
@ -45,14 +45,41 @@
|
||||
#include <xcb/xcb.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
|
||||
class QXcbConnection;
|
||||
class QXcbScreen;
|
||||
class QXcbClipboard;
|
||||
class QXcbClipboardMime;
|
||||
|
||||
class QXcbClipboardTransaction : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QXcbClipboardTransaction(QXcbClipboard *clipboard, xcb_window_t w, xcb_atom_t p,
|
||||
QByteArray d, xcb_atom_t t, int f);
|
||||
~QXcbClipboardTransaction();
|
||||
|
||||
bool updateIncrementalProperty(const xcb_property_notify_event_t *event);
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *ev) override;
|
||||
|
||||
private:
|
||||
QXcbClipboard *m_clipboard;
|
||||
xcb_window_t m_window;
|
||||
xcb_atom_t m_property;
|
||||
QByteArray m_data;
|
||||
xcb_atom_t m_target;
|
||||
uint8_t m_format;
|
||||
uint m_offset = 0;
|
||||
int m_abortTimerId = 0;
|
||||
};
|
||||
|
||||
class QXcbClipboard : public QXcbObject, public QPlatformClipboard
|
||||
{
|
||||
public:
|
||||
@ -81,13 +108,16 @@ public:
|
||||
|
||||
QByteArray getDataInFormat(xcb_atom_t modeAtom, xcb_atom_t fmtatom);
|
||||
|
||||
void setProcessIncr(bool process) { m_incr_active = process; }
|
||||
bool processIncr() { return m_incr_active; }
|
||||
void incrTransactionPeeker(xcb_generic_event_t *ge, bool &accepted);
|
||||
bool handlePropertyNotify(const xcb_generic_event_t *event);
|
||||
|
||||
xcb_window_t getSelectionOwner(xcb_atom_t atom) const;
|
||||
QByteArray getSelection(xcb_atom_t selection, xcb_atom_t target, xcb_atom_t property, xcb_timestamp_t t = 0);
|
||||
|
||||
int increment() const { return m_increment; }
|
||||
int clipboardTimeout() const { return clipboard_timeout; }
|
||||
|
||||
void removeTransaction(xcb_window_t window) { m_transactions.remove(window); }
|
||||
|
||||
private:
|
||||
xcb_generic_event_t *waitForClipboardEvent(xcb_window_t window, int type, bool checkManager = false);
|
||||
|
||||
@ -107,9 +137,12 @@ private:
|
||||
|
||||
static const int clipboard_timeout;
|
||||
|
||||
bool m_incr_active = false;
|
||||
int m_increment = 0;
|
||||
bool m_clipboard_closing = false;
|
||||
xcb_timestamp_t m_incr_receive_time = 0;
|
||||
|
||||
using TransactionMap = QMap<xcb_window_t, QXcbClipboardTransaction *>;
|
||||
TransactionMap m_transactions;
|
||||
};
|
||||
|
||||
#endif // QT_NO_CLIPBOARD
|
||||
|
@ -84,6 +84,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events")
|
||||
Q_LOGGING_CATEGORY(lcQpaEventReader, "qt.qpa.events.reader")
|
||||
Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker")
|
||||
Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard")
|
||||
Q_LOGGING_CATEGORY(lcQpaClipboard, "qt.qpa.clipboard")
|
||||
Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd")
|
||||
|
||||
// this event type was added in libxcb 1.10,
|
||||
@ -105,6 +106,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra
|
||||
|
||||
m_xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP").toLower();
|
||||
|
||||
if (hasXRandr())
|
||||
xrandrSelectEvents();
|
||||
|
||||
initializeScreens();
|
||||
|
||||
#if QT_CONFIG(xcb_xinput)
|
||||
@ -648,6 +652,10 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
|
||||
break;
|
||||
case XCB_PROPERTY_NOTIFY:
|
||||
{
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
if (m_clipboard->handlePropertyNotify(event))
|
||||
break;
|
||||
#endif
|
||||
auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event);
|
||||
if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) {
|
||||
QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window);
|
||||
@ -1007,14 +1015,6 @@ void QXcbConnection::processXcbEvents(QEventLoop::ProcessEventsFlags flags)
|
||||
if (compressEvent(event))
|
||||
continue;
|
||||
|
||||
#ifndef QT_NO_CLIPBOARD
|
||||
bool accepted = false;
|
||||
if (clipboard()->processIncr())
|
||||
clipboard()->incrTransactionPeeker(event, accepted);
|
||||
if (accepted)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
auto isWaitingFor = [=](PeekFunc peekFunc) {
|
||||
// These callbacks return true if the event is what they were
|
||||
// waiting for, remove them from the list in that case.
|
||||
|
@ -68,6 +68,7 @@ Q_DECLARE_LOGGING_CATEGORY(lcQpaScreen)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaEvents)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaPeeker)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaKeyboard)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaClipboard)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaXDnd)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQpaEventReader)
|
||||
|
||||
@ -250,7 +251,7 @@ protected:
|
||||
bool event(QEvent *e) override;
|
||||
|
||||
private:
|
||||
void selectXRandrEvents();
|
||||
void xrandrSelectEvents();
|
||||
QXcbScreen* findScreenForCrtc(xcb_window_t rootWindow, xcb_randr_crtc_t crtc) const;
|
||||
QXcbScreen* findScreenForOutput(xcb_window_t rootWindow, xcb_randr_output_t output) const;
|
||||
QXcbVirtualDesktop* virtualDesktopForRootWindow(xcb_window_t rootWindow) const;
|
||||
|
@ -308,7 +308,7 @@ void QXcbBasicConnection::initializeXRandr()
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasXRender = true;
|
||||
m_hasXRandr = true;
|
||||
m_xrenderVersion.first = xrenderQuery->major_version;
|
||||
m_xrenderVersion.second = xrenderQuery->minor_version;
|
||||
#endif
|
||||
@ -358,7 +358,7 @@ void QXcbBasicConnection::initializeXRender()
|
||||
return;
|
||||
}
|
||||
|
||||
m_hasXRandr = true;
|
||||
m_hasXRender = true;
|
||||
m_xrandrFirstEvent = reply->first_event;
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
#include <xcb/xinerama.h>
|
||||
|
||||
void QXcbConnection::selectXRandrEvents()
|
||||
void QXcbConnection::xrandrSelectEvents()
|
||||
{
|
||||
xcb_screen_iterator_t rootIter = xcb_setup_roots_iterator(setup());
|
||||
for (; rootIter.rem; xcb_screen_next(&rootIter)) {
|
||||
@ -270,8 +270,6 @@ void QXcbConnection::destroyScreen(QXcbScreen *screen)
|
||||
|
||||
void QXcbConnection::initializeScreens()
|
||||
{
|
||||
selectXRandrEvents();
|
||||
|
||||
xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup());
|
||||
int xcbScreenNumber = 0; // screen number in the xcb sense
|
||||
QXcbScreen *primaryScreen = nullptr;
|
||||
@ -284,7 +282,7 @@ void QXcbConnection::initializeScreens()
|
||||
QXcbVirtualDesktop *virtualDesktop = new QXcbVirtualDesktop(this, xcbScreen, xcbScreenNumber);
|
||||
m_virtualDesktops.append(virtualDesktop);
|
||||
QList<QPlatformScreen *> siblings;
|
||||
if (hasXRender()) {
|
||||
if (hasXRandr()) {
|
||||
// RRGetScreenResourcesCurrent is fast but it may return nothing if the
|
||||
// configuration is not initialized wrt to the hardware. We should call
|
||||
// RRGetScreenResources in this case.
|
||||
|
@ -207,7 +207,6 @@ protected:
|
||||
void setTransparentForMouseEvents(bool transparent);
|
||||
void updateDoesNotAcceptFocus(bool doesNotAcceptFocus);
|
||||
|
||||
QRect windowToWmGeometry(QRect r) const;
|
||||
void sendXEmbedMessage(xcb_window_t window, quint32 message,
|
||||
quint32 detail = 0, quint32 data1 = 0, quint32 data2 = 0);
|
||||
void handleXEmbedMessage(const xcb_client_message_event_t *event);
|
||||
|
@ -181,10 +181,10 @@ void QXdgDesktopPortalFileDialog::openPortal()
|
||||
|
||||
if (d->saveFile) {
|
||||
if (!d->directory.isEmpty())
|
||||
options.insert(QLatin1String("current_folder"), d->directory.toLatin1());
|
||||
options.insert(QLatin1String("current_folder"), d->directory.toLatin1().append('\0'));
|
||||
|
||||
if (!d->selectedFiles.isEmpty())
|
||||
options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1());
|
||||
options.insert(QLatin1String("current_file"), d->selectedFiles.first().toLatin1().append('\0'));
|
||||
}
|
||||
|
||||
// Insert filters
|
||||
|
@ -64,6 +64,9 @@ struct TestData
|
||||
quint16 data16;
|
||||
quint8 data8;
|
||||
|
||||
float dataFloat;
|
||||
double dataDouble;
|
||||
|
||||
quint8 reserved;
|
||||
};
|
||||
|
||||
@ -72,6 +75,7 @@ template <> quint8 getData(const TestData &d) { return d.data8; }
|
||||
template <> quint16 getData(const TestData &d) { return d.data16; }
|
||||
template <> quint32 getData(const TestData &d) { return d.data32; }
|
||||
template <> quint64 getData(const TestData &d) { return d.data64; }
|
||||
template <> float getData(const TestData &d) { return d.dataFloat; }
|
||||
|
||||
union RawTestData
|
||||
{
|
||||
@ -79,9 +83,39 @@ union RawTestData
|
||||
TestData data;
|
||||
};
|
||||
|
||||
static const TestData inNativeEndian = { Q_UINT64_C(0x0123456789abcdef), 0x00c0ffee, 0xcafe, 0xcf, '\0' };
|
||||
static const RawTestData inBigEndian = { "\x01\x23\x45\x67\x89\xab\xcd\xef" "\x00\xc0\xff\xee" "\xca\xfe" "\xcf" };
|
||||
static const RawTestData inLittleEndian = { "\xef\xcd\xab\x89\x67\x45\x23\x01" "\xee\xff\xc0\x00" "\xfe\xca" "\xcf" };
|
||||
template <typename Float>
|
||||
Float int2Float(typename QIntegerForSizeof<Float>::Unsigned i)
|
||||
{
|
||||
Float result = 0;
|
||||
memcpy(reinterpret_cast<char *>(&result), reinterpret_cast<const char *>(&i), sizeof (Float));
|
||||
return result;
|
||||
}
|
||||
|
||||
static const TestData inNativeEndian = {
|
||||
Q_UINT64_C(0x0123456789abcdef),
|
||||
0x00c0ffee,
|
||||
0xcafe,
|
||||
0xcf,
|
||||
int2Float<float>(0x00c0ffeeU),
|
||||
int2Float<double>(Q_UINT64_C(0x0123456789abcdef)),
|
||||
'\0'
|
||||
};
|
||||
static const RawTestData inBigEndian = {
|
||||
"\x01\x23\x45\x67\x89\xab\xcd\xef"
|
||||
"\x00\xc0\xff\xee"
|
||||
"\xca\xfe"
|
||||
"\xcf"
|
||||
"\x00\xc0\xff\xee"
|
||||
"\x01\x23\x45\x67\x89\xab\xcd\xef"
|
||||
};
|
||||
static const RawTestData inLittleEndian = {
|
||||
"\xef\xcd\xab\x89\x67\x45\x23\x01"
|
||||
"\xee\xff\xc0\x00"
|
||||
"\xfe\xca"
|
||||
"\xcf"
|
||||
"\xee\xff\xc0\x00"
|
||||
"\xef\xcd\xab\x89\x67\x45\x23\x01"
|
||||
};
|
||||
|
||||
#define EXPAND_ENDIAN_TEST(endian) \
|
||||
do { \
|
||||
|
@ -209,9 +209,6 @@ void tst_QIODevice::read_QByteArray()
|
||||
//--------------------------------------------------------------------
|
||||
void tst_QIODevice::unget()
|
||||
{
|
||||
#if defined(Q_OS_MAC)
|
||||
QSKIP("The unget network test is unstable on Mac. See QTBUG-39983.");
|
||||
#endif
|
||||
QBuffer buffer;
|
||||
buffer.open(QBuffer::ReadWrite);
|
||||
buffer.write("ZXCV");
|
||||
|
@ -1,7 +1,5 @@
|
||||
[sendPostedEvents]
|
||||
windows
|
||||
osx
|
||||
[registerTimer]
|
||||
windows
|
||||
osx
|
||||
winrt
|
||||
|
@ -103,6 +103,7 @@ private slots:
|
||||
void deleteQObjectWhenDeletingEvent();
|
||||
void overloads();
|
||||
void isSignalConnected();
|
||||
void isSignalConnectedAfterDisconnection();
|
||||
void qMetaObjectConnect();
|
||||
void qMetaObjectDisconnectOne();
|
||||
void sameName();
|
||||
@ -3837,6 +3838,58 @@ void tst_QObject::isSignalConnected()
|
||||
QVERIFY(!o.isSignalConnected(QMetaMethod()));
|
||||
}
|
||||
|
||||
void tst_QObject::isSignalConnectedAfterDisconnection()
|
||||
{
|
||||
ManySignals o;
|
||||
const QMetaObject *meta = o.metaObject();
|
||||
|
||||
const QMetaMethod sig00 = meta->method(meta->indexOfSignal("sig00()"));
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
QObject::connect(&o, &ManySignals::sig00, qt_noop);
|
||||
QVERIFY(o.isSignalConnected(sig00));
|
||||
QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0));
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
|
||||
const QMetaMethod sig69 = meta->method(meta->indexOfSignal("sig69()"));
|
||||
QVERIFY(!o.isSignalConnected(sig69));
|
||||
QObject::connect(&o, &ManySignals::sig69, qt_noop);
|
||||
QVERIFY(o.isSignalConnected(sig69));
|
||||
QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0));
|
||||
QVERIFY(!o.isSignalConnected(sig69));
|
||||
|
||||
{
|
||||
ManySignals o2;
|
||||
QObject::connect(&o, &ManySignals::sig00, &o2, &ManySignals::sig00);
|
||||
QVERIFY(o.isSignalConnected(sig00));
|
||||
// o2 is destructed
|
||||
}
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
|
||||
const QMetaMethod sig01 = meta->method(meta->indexOfSignal("sig01()"));
|
||||
QObject::connect(&o, &ManySignals::sig00, qt_noop);
|
||||
QObject::connect(&o, &ManySignals::sig01, qt_noop);
|
||||
QObject::connect(&o, &ManySignals::sig69, qt_noop);
|
||||
QVERIFY(o.isSignalConnected(sig00));
|
||||
QVERIFY(o.isSignalConnected(sig01));
|
||||
QVERIFY(o.isSignalConnected(sig69));
|
||||
QVERIFY(QObject::disconnect(&o, &ManySignals::sig69, 0, 0));
|
||||
QVERIFY(o.isSignalConnected(sig00));
|
||||
QVERIFY(o.isSignalConnected(sig01));
|
||||
QVERIFY(!o.isSignalConnected(sig69));
|
||||
QVERIFY(QObject::disconnect(&o, &ManySignals::sig00, 0, 0));
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
QVERIFY(o.isSignalConnected(sig01));
|
||||
QVERIFY(!o.isSignalConnected(sig69));
|
||||
QObject::connect(&o, &ManySignals::sig69, qt_noop);
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
QVERIFY(o.isSignalConnected(sig01));
|
||||
QVERIFY(o.isSignalConnected(sig69));
|
||||
QVERIFY(QObject::disconnect(&o, &ManySignals::sig01, 0, 0));
|
||||
QVERIFY(!o.isSignalConnected(sig00));
|
||||
QVERIFY(!o.isSignalConnected(sig01));
|
||||
QVERIFY(o.isSignalConnected(sig69));
|
||||
}
|
||||
|
||||
void tst_QObject::qMetaObjectConnect()
|
||||
{
|
||||
ReceiverObject r1;
|
||||
|
@ -334,7 +334,7 @@ void tst_QCborValue::copyCompare()
|
||||
QCOMPARE(v, other);
|
||||
QVERIFY(!(v != other));
|
||||
QVERIFY(!(v < other));
|
||||
#if QT_HAS_INCLUDE(<compare>)
|
||||
#if 0 && QT_HAS_INCLUDE(<compare>)
|
||||
QVERIFY(v <= other);
|
||||
QVERIFY(v >= other);
|
||||
QVERIFY(!(v > other));
|
||||
|
@ -2108,12 +2108,16 @@ void tst_QRegularExpression::threadSafety_data()
|
||||
QTest::addRow("pattern%d", ++i) << "ab.*cd" << subject;
|
||||
}
|
||||
|
||||
// pcre2 does not support JIT for winrt. As this test row takes a long time without JIT we skip
|
||||
// it for winrt as it might time out in COIN.
|
||||
#ifndef Q_OS_WINRT
|
||||
{
|
||||
QString subject = "ab";
|
||||
subject.append(QString(512*1024, QLatin1Char('x')));
|
||||
subject.append("c");
|
||||
QTest::addRow("pattern%d", ++i) << "ab.*cd" << subject;
|
||||
}
|
||||
#endif // Q_OS_WINRT
|
||||
|
||||
{
|
||||
QString subject = "ab";
|
||||
|
@ -962,9 +962,6 @@ void tst_QLocalSocket::processConnection()
|
||||
#if !QT_CONFIG(process)
|
||||
QSKIP("No qprocess support", SkipAll);
|
||||
#else
|
||||
#ifdef Q_OS_MAC
|
||||
QSKIP("The processConnection test is unstable on Mac. See QTBUG-39986.");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
const QString exeSuffix = QStringLiteral(".exe");
|
||||
|
@ -51,10 +51,15 @@
|
||||
|
||||
// Will try to wait for the condition while allowing event processing
|
||||
// for a maximum of 5 seconds.
|
||||
#define TRY_WAIT(expr) \
|
||||
#define TRY_WAIT(expr, timedOut) \
|
||||
do { \
|
||||
*timedOut = true; \
|
||||
const int step = 50; \
|
||||
for (int __i = 0; __i < 5000 && !(expr); __i+=step) { \
|
||||
for (int __i = 0; __i < 5000; __i += step) { \
|
||||
if (expr) { \
|
||||
*timedOut = false; \
|
||||
break; \
|
||||
} \
|
||||
QTest::qWait(step); \
|
||||
} \
|
||||
} while(0)
|
||||
@ -123,6 +128,8 @@ private slots:
|
||||
|
||||
protected:
|
||||
bool createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount = 0, const QStringList &intial_dirs = QStringList());
|
||||
QModelIndex prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2 = nullptr,
|
||||
QSignalSpy **spy3 = nullptr);
|
||||
|
||||
private:
|
||||
QFileSystemModel *model;
|
||||
@ -306,7 +313,11 @@ void tst_QFileSystemModel::iconProvider()
|
||||
bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringList &initial_files, int existingFileCount, const QStringList &initial_dirs)
|
||||
{
|
||||
//qDebug() << (model->rowCount(model->index(test_path))) << existingFileCount << initial_files;
|
||||
TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount));
|
||||
bool timedOut = false;
|
||||
TRY_WAIT((model->rowCount(model->index(test_path)) == existingFileCount), &timedOut);
|
||||
if (timedOut)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < initial_dirs.count(); ++i) {
|
||||
QDir dir(test_path);
|
||||
if (!dir.exists()) {
|
||||
@ -363,23 +374,45 @@ bool tst_QFileSystemModel::createFiles(const QString &test_path, const QStringLi
|
||||
return true;
|
||||
}
|
||||
|
||||
void tst_QFileSystemModel::rowCount()
|
||||
QModelIndex tst_QFileSystemModel::prepareTestModelRoot(const QString &test_path, QSignalSpy **spy2,
|
||||
QSignalSpy **spy3)
|
||||
{
|
||||
QString tmp = flatDirTestPath;
|
||||
QVERIFY(createFiles(tmp, QStringList()));
|
||||
if (model->rowCount(model->index(test_path)) != 0)
|
||||
return QModelIndex();
|
||||
|
||||
QSignalSpy spy2(model, SIGNAL(rowsInserted(QModelIndex,int,int)));
|
||||
QSignalSpy spy3(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)));
|
||||
if (spy2)
|
||||
*spy2 = new QSignalSpy(model, &QFileSystemModel::rowsInserted);
|
||||
if (spy3)
|
||||
*spy3 = new QSignalSpy(model, &QFileSystemModel::rowsAboutToBeInserted);
|
||||
|
||||
QStringList files = QStringList() << "b" << "d" << "f" << "h" << "j" << ".a" << ".c" << ".e" << ".g";
|
||||
QStringList files = { "b", "d", "f", "h", "j", ".a", ".c", ".e", ".g" };
|
||||
QString l = "b,d,f,h,j,.a,.c,.e,.g";
|
||||
|
||||
QVERIFY(createFiles(tmp, files));
|
||||
if (!createFiles(test_path, files))
|
||||
return QModelIndex();
|
||||
|
||||
QModelIndex root = model->setRootPath(tmp);
|
||||
QTRY_COMPARE(model->rowCount(root), 5);
|
||||
QVERIFY(spy2.count() > 0);
|
||||
QVERIFY(spy3.count() > 0);
|
||||
QModelIndex root = model->setRootPath(test_path);
|
||||
if (!root.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
bool timedOut = false;
|
||||
TRY_WAIT(model->rowCount(root) == 5, &timedOut);
|
||||
if (timedOut)
|
||||
return QModelIndex();
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
void tst_QFileSystemModel::rowCount()
|
||||
{
|
||||
const QString tmp = flatDirTestPath;
|
||||
QSignalSpy *spy2 = nullptr;
|
||||
QSignalSpy *spy3 = nullptr;
|
||||
QModelIndex root = prepareTestModelRoot(flatDirTestPath, &spy2, &spy3);
|
||||
QVERIFY(root.isValid());
|
||||
|
||||
QVERIFY(spy2 && spy2->count() > 0);
|
||||
QVERIFY(spy3 && spy3->count() > 0);
|
||||
}
|
||||
|
||||
void tst_QFileSystemModel::rowsInserted_data()
|
||||
@ -401,9 +434,9 @@ static inline QString lastEntry(const QModelIndex &root)
|
||||
|
||||
void tst_QFileSystemModel::rowsInserted()
|
||||
{
|
||||
QString tmp = flatDirTestPath;
|
||||
rowCount();
|
||||
QModelIndex root = model->index(model->rootPath());
|
||||
const QString tmp = flatDirTestPath;
|
||||
QModelIndex root = prepareTestModelRoot(tmp);
|
||||
QVERIFY(root.isValid());
|
||||
|
||||
QFETCH(int, ascending);
|
||||
QFETCH(int, count);
|
||||
@ -454,9 +487,9 @@ void tst_QFileSystemModel::rowsRemoved_data()
|
||||
|
||||
void tst_QFileSystemModel::rowsRemoved()
|
||||
{
|
||||
QString tmp = flatDirTestPath;
|
||||
rowCount();
|
||||
QModelIndex root = model->index(model->rootPath());
|
||||
const QString tmp = flatDirTestPath;
|
||||
QModelIndex root = prepareTestModelRoot(tmp);
|
||||
QVERIFY(root.isValid());
|
||||
|
||||
QFETCH(int, count);
|
||||
QFETCH(int, ascending);
|
||||
@ -509,9 +542,9 @@ void tst_QFileSystemModel::dataChanged()
|
||||
{
|
||||
QSKIP("This can't be tested right now since we don't watch files, only directories.");
|
||||
|
||||
QString tmp = flatDirTestPath;
|
||||
rowCount();
|
||||
QModelIndex root = model->index(model->rootPath());
|
||||
const QString tmp = flatDirTestPath;
|
||||
QModelIndex root = prepareTestModelRoot(tmp);
|
||||
QVERIFY(root.isValid());
|
||||
|
||||
QFETCH(int, count);
|
||||
QFETCH(int, assending);
|
||||
|
Loading…
x
Reference in New Issue
Block a user