Merge remote-tracking branch 'origin/5.12' into dev

Change-Id: I6f8d3abd3247dc980dc7834801a017a89c8f4286
This commit is contained in:
Qt Forward Merge Bot 2018-11-01 01:01:28 +01:00
commit f09fc1f352
28 changed files with 435 additions and 207 deletions

View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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" },

View File

@ -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;

View File

@ -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)

View File

@ -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;

View File

@ -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));

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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 { \

View File

@ -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");

View File

@ -1,7 +1,5 @@
[sendPostedEvents]
windows
osx
[registerTimer]
windows
osx
winrt

View File

@ -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;

View File

@ -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));

View File

@ -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";

View File

@ -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");

View File

@ -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);