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

Change-Id: Icc9b061c56e969756f0351c936cdeb8063c86079
This commit is contained in:
Qt Forward Merge Bot 2019-02-28 01:00:14 +01:00
commit 043f99954f
24 changed files with 375 additions and 41 deletions

View File

@ -17,7 +17,7 @@ QMAKE_EXTENSION_SHLIB = dylib
QMAKE_EXTENSIONS_AUX_SHLIB = tbd QMAKE_EXTENSIONS_AUX_SHLIB = tbd
QMAKE_LIBDIR = QMAKE_LIBDIR =
# sdk.prf will prefix the proper SDK sysroot # qtConfLibrary_openglMakeSpec will prefix the proper SDK sysroot
QMAKE_INCDIR_OPENGL = \ QMAKE_INCDIR_OPENGL = \
/System/Library/Frameworks/OpenGL.framework/Headers \ /System/Library/Frameworks/OpenGL.framework/Headers \
/System/Library/Frameworks/AGL.framework/Headers/ /System/Library/Frameworks/AGL.framework/Headers/

View File

@ -33,10 +33,6 @@ QMAKE_MAC_SDK_PATH = $$xcodeSDKInfo(Path)
QMAKE_MAC_SDK_PLATFORM_PATH = $$xcodeSDKInfo(PlatformPath) QMAKE_MAC_SDK_PLATFORM_PATH = $$xcodeSDKInfo(PlatformPath)
QMAKE_MAC_SDK_VERSION = $$xcodeSDKInfo(SDKVersion) QMAKE_MAC_SDK_VERSION = $$xcodeSDKInfo(SDKVersion)
sysrootified =
for(val, QMAKE_INCDIR_OPENGL): sysrootified += $${QMAKE_MAC_SDK_PATH}$$val
QMAKE_INCDIR_OPENGL = $$sysrootified
QMAKESPEC_NAME = $$basename(QMAKESPEC) QMAKESPEC_NAME = $$basename(QMAKESPEC)
# Resolve SDK version of various tools # Resolve SDK version of various tools

View File

@ -1454,6 +1454,7 @@ void VcprojGenerator::initTranslationFiles()
vcProject.TranslationFiles.Guid = _GUIDTranslationFiles; vcProject.TranslationFiles.Guid = _GUIDTranslationFiles;
vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS")); vcProject.TranslationFiles.addFiles(project->values("TRANSLATIONS"));
vcProject.TranslationFiles.addFiles(project->values("EXTRA_TRANSLATIONS"));
vcProject.TranslationFiles.Project = this; vcProject.TranslationFiles.Project = this;
vcProject.TranslationFiles.Config = &(vcProject.Configuration); vcProject.TranslationFiles.Config = &(vcProject.Configuration);
@ -1576,7 +1577,7 @@ void VcprojGenerator::initExtraCompilerOutputs()
const ProStringList &tmp_in = project->values(project->first(ProKey(*it + ".input")).toKey()); const ProStringList &tmp_in = project->values(project->first(ProKey(*it + ".input")).toKey());
for (int i = 0; i < tmp_in.count(); ++i) { for (int i = 0; i < tmp_in.count(); ++i) {
const QString &filename = tmp_in.at(i).toQString(); const QString &filename = tmp_in.at(i).toQString();
if (extraCompilerSources.contains(filename)) if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
extraCompile.addFile(Option::fixPathToTargetOS( extraCompile.addFile(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(filename, tmp_out, QString(), NoShell), false)); replaceExtraCompilerVariables(filename, tmp_out, QString(), NoShell), false));
} }
@ -1592,7 +1593,7 @@ void VcprojGenerator::initExtraCompilerOutputs()
const ProStringList &tmp_in = project->values(inputVar.toKey()); const ProStringList &tmp_in = project->values(inputVar.toKey());
for (int i = 0; i < tmp_in.count(); ++i) { for (int i = 0; i < tmp_in.count(); ++i) {
const QString &filename = tmp_in.at(i).toQString(); const QString &filename = tmp_in.at(i).toQString();
if (extraCompilerSources.contains(filename)) if (extraCompilerSources.contains(filename) && !otherFiltersContain(filename))
extraCompile.addFile(Option::fixPathToTargetOS( extraCompile.addFile(Option::fixPathToTargetOS(
replaceExtraCompilerVariables(filename, QString(), QString(), NoShell), false)); replaceExtraCompilerVariables(filename, QString(), QString(), NoShell), false));
} }
@ -1606,6 +1607,28 @@ void VcprojGenerator::initExtraCompilerOutputs()
} }
} }
bool VcprojGenerator::otherFiltersContain(const QString &fileName) const
{
auto filterFileMatches = [&fileName] (const VCFilterFile &ff)
{
return ff.file == fileName;
};
for (const VCFilter *filter : { &vcProject.RootFiles,
&vcProject.SourceFiles,
&vcProject.HeaderFiles,
&vcProject.GeneratedFiles,
&vcProject.LexYaccFiles,
&vcProject.TranslationFiles,
&vcProject.FormFiles,
&vcProject.ResourceFiles,
&vcProject.DeploymentFiles,
&vcProject.DistributionFiles}) {
if (std::any_of(filter->Files.cbegin(), filter->Files.cend(), filterFileMatches))
return true;
}
return false;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -132,6 +132,7 @@ private:
ProString firstInputFileName(const ProString &extraCompilerName) const; ProString firstInputFileName(const ProString &extraCompilerName) const;
QString firstExpandedOutputFileName(const ProString &extraCompilerName); QString firstExpandedOutputFileName(const ProString &extraCompilerName);
void createCustomBuildToolFakeFile(const QString &cbtFilePath, const QString &realOutFilePath); void createCustomBuildToolFakeFile(const QString &cbtFilePath, const QString &realOutFilePath);
bool otherFiltersContain(const QString &fileName) const;
friend class VCFilter; friend class VCFilter;
}; };

View File

@ -2676,9 +2676,9 @@ QStringList QCoreApplication::libraryPaths()
QStringList *app_libpaths = new QStringList; QStringList *app_libpaths = new QStringList;
coreappdata()->app_libpaths.reset(app_libpaths); coreappdata()->app_libpaths.reset(app_libpaths);
const QByteArray libPathEnv = qgetenv("QT_PLUGIN_PATH"); QString libPathEnv = qEnvironmentVariable("QT_PLUGIN_PATH");
if (!libPathEnv.isEmpty()) { if (!libPathEnv.isEmpty()) {
QStringList paths = QFile::decodeName(libPathEnv).split(QDir::listSeparator(), QString::SkipEmptyParts); QStringList paths = libPathEnv.split(QDir::listSeparator(), QString::SkipEmptyParts);
for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) { for (QStringList::const_iterator it = paths.constBegin(); it != paths.constEnd(); ++it) {
QString canonicalPath = QDir(*it).canonicalPath(); QString canonicalPath = QDir(*it).canonicalPath();
if (!canonicalPath.isEmpty() if (!canonicalPath.isEmpty()

View File

@ -95,7 +95,7 @@ class QEventDispatcherWin32Private;
LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp); LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPARAM lp);
QEventDispatcherWin32Private::QEventDispatcherWin32Private() QEventDispatcherWin32Private::QEventDispatcherWin32Private()
: threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0), : threadId(GetCurrentThreadId()), interrupt(false), internalHwnd(0),
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL) wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
{ {
@ -552,7 +552,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
wakeUp(); // trigger a call to sendPostedEvents() wakeUp(); // trigger a call to sendPostedEvents()
} }
d->interrupt = false; d->interrupt.store(false);
emit awake(); emit awake();
bool canWait; bool canWait;
@ -568,7 +568,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
pHandles = &d->winEventNotifierActivatedEvent; pHandles = &d->winEventNotifierActivatedEvent;
} }
QVarLengthArray<MSG> processedTimers; QVarLengthArray<MSG> processedTimers;
while (!d->interrupt) { while (!d->interrupt.load()) {
MSG msg; MSG msg;
bool haveMessage; bool haveMessage;
@ -649,7 +649,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
// still nothing - wait for message or signalled objects // still nothing - wait for message or signalled objects
canWait = (!retVal canWait = (!retVal
&& !d->interrupt && !d->interrupt.load()
&& (flags & QEventLoop::WaitForMoreEvents)); && (flags & QEventLoop::WaitForMoreEvents));
if (canWait) { if (canWait) {
emit aboutToBlock(); emit aboutToBlock();
@ -1022,7 +1022,7 @@ void QEventDispatcherWin32::wakeUp()
void QEventDispatcherWin32::interrupt() void QEventDispatcherWin32::interrupt()
{ {
Q_D(QEventDispatcherWin32); Q_D(QEventDispatcherWin32);
d->interrupt = true; d->interrupt.store(true);
wakeUp(); wakeUp();
} }

View File

@ -165,8 +165,7 @@ public:
DWORD threadId; DWORD threadId;
bool interrupt; QAtomicInt interrupt;
bool closingDown;
// internal window handle used for socketnotifiers/timers/etc // internal window handle used for socketnotifiers/timers/etc
HWND internalHwnd; HWND internalHwnd;
@ -193,9 +192,11 @@ public:
void postActivateSocketNotifiers(); void postActivateSocketNotifiers();
void doWsaAsyncSelect(int socket, long event); void doWsaAsyncSelect(int socket, long event);
bool closingDown = false;
bool winEventNotifierListModified = false;
HANDLE winEventNotifierActivatedEvent; HANDLE winEventNotifierActivatedEvent;
QList<QWinEventNotifier *> winEventNotifierList; QList<QWinEventNotifier *> winEventNotifierList;
bool winEventNotifierListModified = false;
void activateEventNotifier(QWinEventNotifier * wen); void activateEventNotifier(QWinEventNotifier * wen);
QList<MSG> queuedUserInputEvents; QList<MSG> queuedUserInputEvents;

View File

@ -2175,8 +2175,10 @@ void QObject::removeEventFilter(QObject *obj)
Note that entering and leaving a new event loop (e.g., by opening a modal Note that entering and leaving a new event loop (e.g., by opening a modal
dialog) will \e not perform the deferred deletion; for the object to be dialog) will \e not perform the deferred deletion; for the object to be
deleted, the control must return to the event loop from which deleted, the control must return to the event loop from which deleteLater()
deleteLater() was called. was called. This does not apply to objects deleted while a previous, nested
event loop was still running: the Qt event loop will delete those objects
as soon as the new nested event loop starts.
\b{Note:} It is safe to call this function more than once; when the \b{Note:} It is safe to call this function more than once; when the
first deferred deletion event is delivered, any pending events for the first deferred deletion event is delivered, any pending events for the

View File

@ -448,7 +448,7 @@
], ],
"sources": [ "sources": [
{ "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" }, { "type": "pkgConfig", "args": "gl", "condition": "!config.darwin" },
{ "type": "makeSpec", "spec": "OPENGL" } { "type": "openglMakeSpec" }
] ]
}, },
"opengl_es2": { "opengl_es2": {

View File

@ -15,6 +15,17 @@ defineTest(qtConfLibrary_freetype) {
return(true) return(true)
} }
defineTest(qtConfLibrary_openglMakeSpec) {
darwin:sdk {
sysrootified =
for(val, QMAKE_INCDIR_OPENGL): sysrootified += $${QMAKE_MAC_SDK_PATH}$$val
QMAKE_INCDIR_OPENGL = $$sysrootified
}
$${1}.spec = OPENGL
!qtConfLibrary_makeSpec($$1, $$2): return(false)
return(true)
}
# Check for Direct X shader compiler 'fxc'. # Check for Direct X shader compiler 'fxc'.
# Up to Direct X SDK June 2010 and for MinGW, this is pointed to by the # Up to Direct X SDK June 2010 and for MinGW, this is pointed to by the
# DXSDK_DIR variable. Starting with Windows Kit 8, it is included in # DXSDK_DIR variable. Starting with Windows Kit 8, it is included in

View File

@ -695,13 +695,29 @@ QList<QTouchEvent::TouchPoint>
} }
if (states == Qt::TouchPointReleased) { if (states == Qt::TouchPointReleased) {
g_nextPointId = 1; // All points on deviceId have been released.
g_pointIdMap->clear(); // Remove all points associated with that device from g_pointIdMap.
// (On other devices, some touchpoints might still be pressed.
// But this function is only called with points from one device at a time.)
for (auto it = g_pointIdMap->begin(); it != g_pointIdMap->end();) {
if (it.key() >> 32 == quint64(deviceId))
it = g_pointIdMap->erase(it);
else
++it;
}
if (g_pointIdMap->isEmpty())
g_nextPointId = 1;
} }
return touchPoints; return touchPoints;
} }
void QWindowSystemInterfacePrivate::clearPointIdMap()
{
g_pointIdMap->clear();
g_nextPointId = 1;
}
QList<QWindowSystemInterface::TouchPoint> QList<QWindowSystemInterface::TouchPoint>
QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, QWindowSystemInterfacePrivate::toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
const QWindow *window) const QWindow *window)

View File

@ -537,6 +537,7 @@ public:
static QList<QWindowSystemInterface::TouchPoint> static QList<QWindowSystemInterface::TouchPoint>
toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList, toNativeTouchPoints(const QList<QTouchEvent::TouchPoint>& pointList,
const QWindow *window); const QWindow *window);
static void clearPointIdMap();
static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler); static void installWindowSystemEventHandler(QWindowSystemEventHandler *handler);
static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler); static void removeWindowSystemEventhandler(QWindowSystemEventHandler *handler);

View File

@ -297,7 +297,7 @@ void QSyntaxHighlighterPrivate::reformatBlock(const QTextBlock &block)
QSyntaxHighlighter::QSyntaxHighlighter(QObject *parent) QSyntaxHighlighter::QSyntaxHighlighter(QObject *parent)
: QObject(*new QSyntaxHighlighterPrivate, parent) : QObject(*new QSyntaxHighlighterPrivate, parent)
{ {
if (parent->inherits("QTextEdit")) { if (parent && parent->inherits("QTextEdit")) {
QTextDocument *doc = parent->property("document").value<QTextDocument *>(); QTextDocument *doc = parent->property("document").value<QTextDocument *>();
if (doc) if (doc)
setDocument(doc); setDocument(doc);

View File

@ -62,9 +62,6 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
QEglFSScreen::~QEglFSScreen() QEglFSScreen::~QEglFSScreen()
{ {
delete m_cursor; delete m_cursor;
#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
#endif
} }
QRect QEglFSScreen::geometry() const QRect QEglFSScreen::geometry() const

View File

@ -62,6 +62,7 @@ QEglFSWindow::QEglFSWindow(QWindow *w)
: QPlatformWindow(w), : QPlatformWindow(w),
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
m_backingStore(0), m_backingStore(0),
m_rasterCompositingContext(0),
#endif #endif
m_raster(false), m_raster(false),
m_winId(0), m_winId(0),
@ -144,18 +145,18 @@ void QEglFSWindow::create()
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
if (isRaster()) { if (isRaster()) {
QOpenGLContext *context = new QOpenGLContext(QGuiApplication::instance()); m_rasterCompositingContext = new QOpenGLContext;
context->setShareContext(qt_gl_global_share_context()); m_rasterCompositingContext->setShareContext(qt_gl_global_share_context());
context->setFormat(m_format); m_rasterCompositingContext->setFormat(m_format);
context->setScreen(window()->screen()); m_rasterCompositingContext->setScreen(window()->screen());
if (Q_UNLIKELY(!context->create())) if (Q_UNLIKELY(!m_rasterCompositingContext->create()))
qFatal("EGLFS: Failed to create compositing context"); qFatal("EGLFS: Failed to create compositing context");
compositor->setTarget(context, window(), screen->rawGeometry()); compositor->setTarget(m_rasterCompositingContext, window(), screen->rawGeometry());
compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION")); compositor->setRotation(qEnvironmentVariableIntValue("QT_QPA_EGLFS_ROTATION"));
// If there is a "root" window into which raster and QOpenGLWidget content is // If there is a "root" window into which raster and QOpenGLWidget content is
// composited, all other contexts must share with its context. // composited, all other contexts must share with its context.
if (!qt_gl_global_share_context()) { if (!qt_gl_global_share_context()) {
qt_gl_set_global_share_context(context); qt_gl_set_global_share_context(m_rasterCompositingContext);
// What we set up here is in effect equivalent to the application setting // What we set up here is in effect equivalent to the application setting
// AA_ShareOpenGLContexts. Set the attribute to be fully consistent. // AA_ShareOpenGLContexts. Set the attribute to be fully consistent.
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
@ -166,6 +167,10 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy() void QEglFSWindow::destroy()
{ {
#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this);
#endif
QEglFSScreen *screen = this->screen(); QEglFSScreen *screen = this->screen();
if (m_flags.testFlag(HasNativeWindow)) { if (m_flags.testFlag(HasNativeWindow)) {
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
@ -177,12 +182,14 @@ void QEglFSWindow::destroy()
screen->setPrimarySurface(EGL_NO_SURFACE); screen->setPrimarySurface(EGL_NO_SURFACE);
invalidateSurface(); invalidateSurface();
#ifndef QT_NO_OPENGL
QOpenGLCompositor::destroy();
delete m_rasterCompositingContext;
#endif
} }
m_flags = 0; m_flags = 0;
#ifndef QT_NO_OPENGL
QOpenGLCompositor::instance()->removeWindow(this);
#endif
} }
void QEglFSWindow::invalidateSurface() void QEglFSWindow::invalidateSurface()

View File

@ -116,6 +116,7 @@ public:
protected: protected:
#ifndef QT_NO_OPENGL #ifndef QT_NO_OPENGL
QOpenGLCompositorBackingStore *m_backingStore; QOpenGLCompositorBackingStore *m_backingStore;
QOpenGLContext *m_rasterCompositingContext;
#endif #endif
bool m_raster; bool m_raster;
WId m_winId; WId m_winId;

View File

@ -1,6 +1,6 @@
TARGET = qhaiku TARGET = qhaiku
QT += core-private gui-private eventdistpatcher_support-private QT += core-private gui-private eventdispatcher_support-private
SOURCES = \ SOURCES = \
main.cpp \ main.cpp \

View File

@ -1099,6 +1099,12 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
return false; return false;
case QtWindows::ClipboardEvent: case QtWindows::ClipboardEvent:
return false; return false;
case QtWindows::CursorEvent: // Sent to windows that do not have capture (see QTBUG-58590).
if (QWindowsCursor::hasOverrideCursor()) {
QWindowsCursor::enforceOverrideCursor();
return true;
}
break;
case QtWindows::UnknownEvent: case QtWindows::UnknownEvent:
return false; return false;
case QtWindows::AccessibleObjectFromWindowRequest: case QtWindows::AccessibleObjectFromWindowRequest:

View File

@ -1912,7 +1912,7 @@ void QAbstractItemView::mouseReleaseEvent(QMouseEvent *event)
bool click = (index == d->pressedIndex && index.isValid()); bool click = (index == d->pressedIndex && index.isValid());
bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected; bool selectedClicked = click && (event->button() == Qt::LeftButton) && d->pressedAlreadySelected;
EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers); EditTrigger trigger = (selectedClicked ? SelectedClicked : NoEditTriggers);
bool edited = edit(index, trigger, event); const bool edited = click ? edit(index, trigger, event) : false;
d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate; d->ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;

View File

@ -1315,8 +1315,8 @@ void QListView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFl
if (tl.isValid() && br.isValid() if (tl.isValid() && br.isValid()
&& d->isIndexEnabled(tl) && d->isIndexEnabled(tl)
&& d->isIndexEnabled(br)) { && d->isIndexEnabled(br)) {
QRect first = rectForIndex(tl); QRect first = d->cellRectForIndex(tl);
QRect last = rectForIndex(br); QRect last = d->cellRectForIndex(br);
QRect middle; QRect middle;
if (d->flow == LeftToRight) { if (d->flow == LeftToRight) {
QRect &top = first; QRect &top = first;

View File

@ -333,14 +333,31 @@ public:
inline QModelIndex listViewItemToIndex(const QListViewItem &item) const inline QModelIndex listViewItemToIndex(const QListViewItem &item) const
{ return model->index(commonListView->itemIndex(item), column, root); } { return model->index(commonListView->itemIndex(item), column, root); }
inline bool hasRectForIndex(const QModelIndex &index) const
{
return isIndexValid(index) && index.parent() == root && index.column() == column && !isHidden(index.row());
}
QRect rectForIndex(const QModelIndex &index) const QRect rectForIndex(const QModelIndex &index) const
{ {
if (!isIndexValid(index) || index.parent() != root || index.column() != column || isHidden(index.row())) if (!hasRectForIndex(index))
return QRect(); return QRect();
executePostedLayout(); executePostedLayout();
return viewItemRect(indexToListViewItem(index)); return viewItemRect(indexToListViewItem(index));
} }
QRect cellRectForIndex(const QModelIndex &index)
{
if (!hasRectForIndex(index))
return QRect();
executePostedLayout();
auto oldItemAlignment = itemAlignment;
itemAlignment = Qt::Alignment();
const QRect rect = rectForIndex(index);
itemAlignment = oldItemAlignment;
return rect;
}
void viewUpdateGeometries() { q_func()->updateGeometries(); } void viewUpdateGeometries() { q_func()->updateGeometries(); }

View File

@ -204,6 +204,7 @@ private slots:
void basicRawEventTranslationOfIds(); void basicRawEventTranslationOfIds();
void multiPointRawEventTranslationOnTouchScreen(); void multiPointRawEventTranslationOnTouchScreen();
void multiPointRawEventTranslationOnTouchPad(); void multiPointRawEventTranslationOnTouchPad();
void touchOnMultipleTouchscreens();
void deleteInEventHandler(); void deleteInEventHandler();
void deleteInRawEventTranslation(); void deleteInRawEventTranslation();
void crashInQGraphicsSceneAfterNotHandlingTouchBegin(); void crashInQGraphicsSceneAfterNotHandlingTouchBegin();
@ -213,11 +214,13 @@ private slots:
private: private:
QTouchDevice *touchScreenDevice; QTouchDevice *touchScreenDevice;
QTouchDevice *secondaryTouchScreenDevice;
QTouchDevice *touchPadDevice; QTouchDevice *touchPadDevice;
}; };
tst_QTouchEvent::tst_QTouchEvent() tst_QTouchEvent::tst_QTouchEvent()
: touchScreenDevice(QTest::createTouchDevice()) : touchScreenDevice(QTest::createTouchDevice())
, secondaryTouchScreenDevice(QTest::createTouchDevice())
, touchPadDevice(QTest::createTouchDevice(QTouchDevice::TouchPad)) , touchPadDevice(QTest::createTouchDevice(QTouchDevice::TouchPad))
{ {
} }
@ -225,6 +228,7 @@ tst_QTouchEvent::tst_QTouchEvent()
void tst_QTouchEvent::cleanup() void tst_QTouchEvent::cleanup()
{ {
QVERIFY(QGuiApplication::topLevelWindows().isEmpty()); QVERIFY(QGuiApplication::topLevelWindows().isEmpty());
QWindowSystemInterfacePrivate::clearPointIdMap();
} }
void tst_QTouchEvent::qPointerUniqueId() void tst_QTouchEvent::qPointerUniqueId()
@ -951,6 +955,157 @@ void tst_QTouchEvent::multiPointRawEventTranslationOnTouchScreen()
} }
} }
void tst_QTouchEvent::touchOnMultipleTouchscreens()
{
tst_QTouchEventWidget touchWidget;
touchWidget.setWindowTitle(QTest::currentTestFunction());
touchWidget.setAttribute(Qt::WA_AcceptTouchEvents);
touchWidget.setGeometry(100, 100, 400, 300);
touchWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&touchWidget));
QWindow *window = touchWidget.windowHandle();
QPointF pos = touchWidget.rect().center();
QPointF screenPos = touchWidget.mapToGlobal(pos.toPoint());
QPointF delta(10, 10);
QRectF screenGeometry = QApplication::desktop()->screenGeometry(&touchWidget);
QVector<QTouchEvent::TouchPoint> rawTouchPoints(3);
rawTouchPoints[0].setId(0);
rawTouchPoints[1].setId(10);
rawTouchPoints[2].setId(11);
// this should be translated to a TouchBegin
rawTouchPoints[0].setState(Qt::TouchPointPressed);
rawTouchPoints[0].setScreenPos(screenPos);
rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
rawTouchPoints[0].setRawScreenPositions({{12, 34}, {56, 78}});
ulong timestamp = 1234;
QList<QWindowSystemInterface::TouchPoint> nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
QWindowSystemInterface::handleTouchEvent(window, timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(!touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
QCOMPARE(touchWidget.timestamp, timestamp);
QTouchEvent::TouchPoint touchBeginPoint = touchWidget.touchBeginPoints.first();
const int touchPointId = (QTouchDevicePrivate::get(touchScreenDevice)->id << 24) + 1;
const int secTouchPointId = (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 2;
QCOMPARE(touchBeginPoint.id(), touchPointId);
QCOMPARE(touchBeginPoint.state(), rawTouchPoints[0].state());
QCOMPARE(touchBeginPoint.pos(), pos);
// press a point on secondaryTouchScreenDevice
touchWidget.seenTouchBegin = false;
rawTouchPoints[1].setState(Qt::TouchPointPressed);
rawTouchPoints[1].setScreenPos(screenPos);
rawTouchPoints[1].setNormalizedPos(normalized(rawTouchPoints[1].pos(), screenGeometry));
rawTouchPoints[1].setRawScreenPositions({{90, 100}, {110, 120}});
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
QCOMPARE(touchWidget.timestamp, timestamp);
touchBeginPoint = touchWidget.touchBeginPoints[0];
QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 2);
QCOMPARE(touchBeginPoint.state(), rawTouchPoints[1].state());
QCOMPARE(touchBeginPoint.pos(), pos);
// press another point on secondaryTouchScreenDevice
touchWidget.seenTouchBegin = false;
rawTouchPoints[2].setState(Qt::TouchPointPressed);
rawTouchPoints[2].setScreenPos(screenPos);
rawTouchPoints[2].setNormalizedPos(normalized(rawTouchPoints[2].pos(), screenGeometry));
rawTouchPoints[2].setRawScreenPositions({{130, 140}, {150, 160}});
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(!touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchBeginPoints.count(), 1);
QCOMPARE(touchWidget.timestamp, timestamp);
touchBeginPoint = touchWidget.touchBeginPoints[0];
QCOMPARE(touchBeginPoint.id(), (QTouchDevicePrivate::get(secondaryTouchScreenDevice)->id << 24) + 3);
QCOMPARE(touchBeginPoint.state(), rawTouchPoints[2].state());
QCOMPARE(touchBeginPoint.pos(), pos);
// moving the first point should translate to TouchUpdate
rawTouchPoints[0].setState(Qt::TouchPointMoved);
rawTouchPoints[0].setScreenPos(screenPos + delta);
rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchUpdatePoints.count(), 1);
QTouchEvent::TouchPoint touchUpdatePoint = touchWidget.touchUpdatePoints.first();
QCOMPARE(touchUpdatePoint.id(), touchPointId);
QCOMPARE(touchUpdatePoint.state(), rawTouchPoints[0].state());
QCOMPARE(touchUpdatePoint.pos(), pos + delta);
// releasing the first point translates to TouchEnd
rawTouchPoints[0].setState(Qt::TouchPointReleased);
rawTouchPoints[0].setScreenPos(screenPos + delta + delta);
rawTouchPoints[0].setNormalizedPos(normalized(rawTouchPoints[0].pos(), screenGeometry));
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[0], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, touchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchEndPoints.count(), 1);
QTouchEvent::TouchPoint touchEndPoint = touchWidget.touchEndPoints.first();
QCOMPARE(touchEndPoint.id(), touchPointId);
QCOMPARE(touchEndPoint.state(), rawTouchPoints[0].state());
QCOMPARE(touchEndPoint.pos(), pos + delta + delta);
// Widgets don't normally handle this case: if a TouchEnd was seen before, then
// WA_WState_AcceptedTouchBeginEvent will be false, and
// QApplicationPrivate::translateRawTouchEvent will ignore touch events that aren't TouchBegin.
// So we have to set it true. It _did_ in fact accept the touch begin from the secondary device,
// but it also got a TouchEnd from the primary device in the meantime.
touchWidget.setAttribute(Qt::WA_WState_AcceptedTouchBeginEvent, true);
// Releasing one point on the secondary touchscreen does not yet generate TouchEnd.
touchWidget.seenTouchEnd = false;
touchWidget.touchEndPoints.clear();
rawTouchPoints[1].setState(Qt::TouchPointReleased);
rawTouchPoints[2].setState(Qt::TouchPointStationary);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[1] << rawTouchPoints[2], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(!touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchUpdatePoints.count(), 2);
QCOMPARE(touchWidget.touchUpdatePoints[0].id(), secTouchPointId);
QCOMPARE(touchWidget.touchUpdatePoints[1].id(), secTouchPointId + 1);
// releasing the last point on the secondary touchscreen translates to TouchEnd
touchWidget.seenTouchEnd = false;
rawTouchPoints[2].setState(Qt::TouchPointReleased);
nativeTouchPoints =
QWindowSystemInterfacePrivate::toNativeTouchPoints(QList<QTouchEvent::TouchPoint>() << rawTouchPoints[2], window);
QWindowSystemInterface::handleTouchEvent(window, ++timestamp, secondaryTouchScreenDevice, nativeTouchPoints);
QCoreApplication::processEvents();
QVERIFY(touchWidget.seenTouchBegin);
QVERIFY(touchWidget.seenTouchUpdate);
QVERIFY(touchWidget.seenTouchEnd);
QCOMPARE(touchWidget.touchEndPoints.count(), 1);
touchEndPoint = touchWidget.touchEndPoints.first();
QCOMPARE(touchEndPoint.id(), secTouchPointId + 1);
QCOMPARE(touchEndPoint.state(), rawTouchPoints[2].state());
}
void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad() void tst_QTouchEvent::multiPointRawEventTranslationOnTouchPad()
{ {
tst_QTouchEventWidget touchWidget; tst_QTouchEventWidget touchWidget;

View File

@ -121,6 +121,7 @@ private slots:
void task254449_draggingItemToNegativeCoordinates(); void task254449_draggingItemToNegativeCoordinates();
void keyboardSearch(); void keyboardSearch();
void shiftSelectionWithNonUniformItemSizes(); void shiftSelectionWithNonUniformItemSizes();
void shiftSelectionWithItemAlignment();
void clickOnViewportClearsSelection(); void clickOnViewportClearsSelection();
void task262152_setModelColumnNavigate(); void task262152_setModelColumnNavigate();
void taskQTBUG_2233_scrollHiddenItems_data(); void taskQTBUG_2233_scrollHiddenItems_data();
@ -1802,6 +1803,51 @@ void tst_QListView::shiftSelectionWithNonUniformItemSizes()
} }
} }
void tst_QListView::shiftSelectionWithItemAlignment()
{
QStringList items;
for (int c = 0; c < 2; c++) {
for (int i = 10; i > 0; i--)
items << QString(i, QLatin1Char('*'));
for (int i = 1; i < 11; i++)
items << QString(i, QLatin1Char('*'));
}
QListView view;
view.setFlow(QListView::TopToBottom);
view.setWrapping(true);
view.setItemAlignment(Qt::AlignLeft);
view.setSelectionMode(QAbstractItemView::ExtendedSelection);
QStringListModel model(items);
view.setModel(&model);
QFont font = view.font();
font.setPixelSize(10);
view.setFont(font);
view.resize(300, view.sizeHintForRow(0) * items.size() / 2 + view.horizontalScrollBar()->height());
view.show();
QApplication::setActiveWindow(&view);
QVERIFY(QTest::qWaitForWindowActive(&view));
QCOMPARE(static_cast<QWidget *>(&view), QApplication::activeWindow());
QModelIndex index1 = view.model()->index(items.size() / 4, 0);
QPoint p = view.visualRect(index1).center();
QVERIFY(view.viewport()->rect().contains(p));
QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p);
QCOMPARE(view.currentIndex(), index1);
QCOMPARE(view.selectionModel()->selectedIndexes().size(), 1);
QModelIndex index2 = view.model()->index(items.size() / 4 * 3, 0);
p = view.visualRect(index2).center();
QVERIFY(view.viewport()->rect().contains(p));
QTest::mouseClick(view.viewport(), Qt::LeftButton, Qt::ShiftModifier, p);
QCOMPARE(view.currentIndex(), index2);
QCOMPARE(view.selectionModel()->selectedIndexes().size(), index2.row() - index1.row() + 1);
}
void tst_QListView::clickOnViewportClearsSelection() void tst_QListView::clickOnViewportClearsSelection()
{ {
QStringList items; QStringList items;

View File

@ -200,6 +200,7 @@ private slots:
void taskQTBUG_45697_crash(); void taskQTBUG_45697_crash();
void taskQTBUG_7232_AllowUserToControlSingleStep(); void taskQTBUG_7232_AllowUserToControlSingleStep();
void taskQTBUG_8376(); void taskQTBUG_8376();
void taskQTBUG_61476();
void testInitialFocus(); void testInitialFocus();
}; };
@ -4806,5 +4807,58 @@ void tst_QTreeView::taskQTBUG_8376()
QCOMPARE(rowHeightLvl1Visible, rowHeightLvl1Visible2); QCOMPARE(rowHeightLvl1Visible, rowHeightLvl1Visible2);
} }
void tst_QTreeView::taskQTBUG_61476()
{
// This checks that if a user clicks on an item to collapse it that it
// does not edit (in this case change the check state) the item that is
// now over the mouse just because it got a release event
QTreeView tv;
QStandardItemModel model;
QStandardItem *lastTopLevel = nullptr;
{
for (int i = 0; i < 4; ++i) {
QStandardItem *item = new QStandardItem(QLatin1String("Row Item"));
item->setCheckable(true);
item->setCheckState(Qt::Checked);
model.appendRow(item);
lastTopLevel = item;
for (int j = 0; j < 2; ++j) {
QStandardItem *childItem = new QStandardItem(QLatin1String("Child row Item"));
childItem->setCheckable(true);
childItem->setCheckState(Qt::Checked);
item->appendRow(childItem);
QStandardItem *grandChild = new QStandardItem(QLatin1String("Grand child row Item"));
grandChild->setCheckable(true);
grandChild->setCheckState(Qt::Checked);
childItem->appendRow(grandChild);
}
}
}
tv.setModel(&model);
tv.expandAll();
// We need it to be this size so that the effect of the collapsing will
// cause the parent item to move to be under the cursor
tv.resize(200, 200);
tv.show();
QVERIFY(QTest::qWaitForWindowActive(&tv));
tv.verticalScrollBar()->setValue(tv.verticalScrollBar()->maximum());
// We want to press specifically right around where a checkbox for the
// parent item could be when collapsing
QTreeViewPrivate *priv = static_cast<QTreeViewPrivate*>(qt_widget_private(&tv));
const QModelIndex mi = lastTopLevel->child(0)->index();
const QRect rect = priv->itemDecorationRect(mi);
const QPoint pos = rect.center();
QTest::mousePress(tv.viewport(), Qt::LeftButton, 0, pos);
if (tv.style()->styleHint(QStyle::SH_ListViewExpand_SelectMouseType, 0, &tv) ==
QEvent::MouseButtonPress)
QTRY_VERIFY(!tv.isExpanded(mi));
QTest::mouseRelease(tv.viewport(), Qt::LeftButton, 0, pos);
QTRY_VERIFY(!tv.isExpanded(mi));
QCOMPARE(lastTopLevel->checkState(), Qt::Checked);
}
QTEST_MAIN(tst_QTreeView) QTEST_MAIN(tst_QTreeView)
#include "tst_qtreeview.moc" #include "tst_qtreeview.moc"