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

Change-Id: I8cad26f17834dbc9f7151edc0f17786f9e32025d
This commit is contained in:
Qt Forward Merge Bot 2019-02-15 01:00:50 +01:00
commit ef2ddcf551
37 changed files with 464 additions and 511 deletions

View File

@ -7,4 +7,3 @@ or follow one of these links:
Mac OS X: http://doc.qt.io/qt-%SHORTVERSION%/osx-building.html
Windows: http://doc.qt.io/qt-%SHORTVERSION%/windows-building.html
X11 Platforms: http://doc.qt.io/qt-%SHORTVERSION%/linux-building.html
Windows CE: http://doc.qt.io/qt-%SHORTVERSION%/install-wince.html

View File

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

View File

@ -113,4 +113,9 @@ greaterThan(QMAKE_MSC_VER, 1910) {
COMPAT_MKSPEC =
}
greaterThan(QMAKE_MSC_VER, 1919) {
# Visual Studio 2019 (16.0) / Visual C++ 19.20 and up
MSVC_VER = 16.0
}
!isEmpty(COMPAT_MKSPEC):!$$COMPAT_MKSPEC: CONFIG += $$COMPAT_MKSPEC

View File

@ -20,6 +20,10 @@ QMAKE_INCDIR_OPENVG = $${QMAKE_INCDIR_EGL}
QMAKE_LIBS_EGL = -lEGL -lGLESv2
QMAKE_LIBS_OPENVG = -lEGL -lOpenVG -lGLESv2
QMAKE_INCDIR_BCM_HOST = $$[QT_SYSROOT]/opt/vc/include
QMAKE_LIBDIR_BCM_HOST = $$[QT_SYSROOT]/opt/vc/lib
QMAKE_LIBS_BCM_HOST = -lbcm_host
contains(DISTRO, squeeze) {
#Debian Squeeze: Legacy everything
QMAKE_LIBS_OPENGL_ES2 = -lGLESv2 -lEGL

View File

@ -16,6 +16,11 @@ QMAKE_INCDIR_OPENVG = $${QMAKE_INCDIR_EGL}
QMAKE_LIBS_EGL = -lEGL -lGLESv2
QMAKE_LIBS_OPENVG = -lEGL -lOpenVG -lGLESv2
QMAKE_INCDIR_BCM_HOST = $$[QT_SYSROOT]/opt/vc/include
QMAKE_LIBDIR_BCM_HOST = $$[QT_SYSROOT]/opt/vc/lib
QMAKE_LIBS_BCM_HOST = -lbcm_host
QMAKE_CFLAGS += -march=armv7-a -marm -mthumb-interwork -mfpu=neon-vfpv4 -mtune=cortex-a7 -mabi=aapcs-linux
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS

View File

@ -31,6 +31,10 @@ QMAKE_LIBS_OPENGL_ES2 = $${VC_LINK_LINE} -lGLESv2
# The official opt vc EGL references GLESv2 symbols: need to link it
QMAKE_LIBS_EGL = $${VC_LINK_LINE} -lEGL -lGLESv2
QMAKE_LIBDIR_BCM_HOST = $$VC_LIBRARY_PATH
QMAKE_INCDIR_BCM_HOST = $$VC_INCLUDE_PATH
QMAKE_LIBS_BCM_HOST = -lbcm_host
QMAKE_CFLAGS = -march=armv8-a -mtune=cortex-a53 -mfpu=crypto-neon-fp-armv8
QMAKE_CXXFLAGS = $$QMAKE_CFLAGS

View File

@ -33,10 +33,6 @@ QMAKE_MAC_SDK_PATH = $$xcodeSDKInfo(Path)
QMAKE_MAC_SDK_PLATFORM_PATH = $$xcodeSDKInfo(PlatformPath)
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)
# Resolve SDK version of various tools

View File

@ -59,6 +59,7 @@
// We are hot - unistd.h should have turned on the specific APIs we requested
#include <features.h>
#include <pthread.h>
#include <dirent.h>
#include <fcntl.h>

View File

@ -55,7 +55,8 @@ static DotNET vsVersionFromString(const char *versionString)
{ "11.0", NET2012 },
{ "12.0", NET2013 },
{ "14.0", NET2015 },
{ "15.0", NET2017 }
{ "15.0", NET2017 },
{ "16.0", NET2019 }
};
DotNET result = NETUnknown;
for (const auto entry : mapping) {

View File

@ -52,7 +52,8 @@ enum DotNET {
NET2012 = 0xb0,
NET2013 = 0xc0,
NET2015 = 0xd0,
NET2017 = 0xe0
NET2017 = 0xe0,
NET2019
};
DotNET vsVersionFromString(const ProString &versionString);

View File

@ -73,7 +73,9 @@ const char _slnHeader120[] = "Microsoft Visual Studio Solution File, Format
const char _slnHeader140[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
"\n# Visual Studio 2015";
const char _slnHeader141[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
"\n# Visual Studio 2017";
"\n# Visual Studio 15";
const char _slnHeader142[] = "Microsoft Visual Studio Solution File, Format Version 12.00"
"\n# Visual Studio Version 16";
// The following UUID _may_ change for later servicepacks...
// If so we need to search through the registry at
// HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\Projects
@ -305,6 +307,8 @@ QString VcprojGenerator::retrievePlatformToolSet() const
return QStringLiteral("v140");
case NET2017:
return QStringLiteral("v141");
case NET2019:
return QStringLiteral("v142");
default:
return QString();
}
@ -531,6 +535,9 @@ void VcprojGenerator::writeSubDirs(QTextStream &t)
}
switch (vcProject.Configuration.CompilerVersion) {
case NET2019:
t << _slnHeader142;
break;
case NET2017:
t << _slnHeader141;
break;
@ -881,6 +888,9 @@ void VcprojGenerator::initProject()
// Own elements -----------------------------
vcProject.Name = project->first("QMAKE_ORIG_TARGET").toQString();
switch (vcProject.Configuration.CompilerVersion) {
case NET2019:
vcProject.Version = "16.00";
break;
case NET2017:
vcProject.Version = "15.00";
break;
@ -1548,14 +1558,14 @@ void VcprojGenerator::initExtraCompilerOutputs()
extraCompile.Filter = "";
extraCompile.Guid = QString(_GUIDExtraCompilerFiles) + "-" + (*it);
// If the extra compiler has a variable_out set the output file
// is added to an other file list, and does not need its own..
bool addOnInput = hasBuiltinCompiler(firstExpandedOutputFileName(*it));
const ProString &tmp_other_out = project->first(ProKey(*it + ".variable_out"));
if (!tmp_other_out.isEmpty() && !addOnInput)
continue;
if (!addOnInput) {
// If the extra compiler has a variable_out set that is already handled
// some other place, ignore it.
const ProString &outputVar = project->first(ProKey(*it + ".variable_out"));
if (!outputVar.isEmpty() && otherFilters.contains(outputVar))
continue;
QString tmp_out = project->first(ProKey(*it + ".output")).toQString();
if (project->values(ProKey(*it + ".CONFIG")).indexOf("combine") != -1) {
// Combined output, only one file result

View File

@ -77,7 +77,12 @@ bool IoUtils::isRelativePath(const QString &path)
&& (path.at(2) == QLatin1Char('/') || path.at(2) == QLatin1Char('\\'))) {
return false;
}
// (... unless, of course, they're UNC, which qmake fails on anyway)
// ... unless, of course, they're UNC:
if (path.length() >= 2
&& (path.at(0).unicode() == '\\' || path.at(0).unicode() == '/')
&& path.at(1) == path.at(0)) {
return false;
}
#else
if (path.startsWith(QLatin1Char('/')))
return false;

View File

@ -48,6 +48,11 @@
#include <UIKit/UIKit.h>
#endif
#include <execinfo.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include <objc/runtime.h>
#include <qdebug.h>
QT_BEGIN_NAMESPACE
@ -127,12 +132,54 @@ QT_USE_NAMESPACE
}
@end
QT_NAMESPACE_ALIAS_OBJC_CLASS(QMacAutoReleasePoolTracker);
QT_BEGIN_NAMESPACE
QMacAutoReleasePool::QMacAutoReleasePool()
: pool([[NSAutoreleasePool alloc] init])
{
[[[QMacAutoReleasePoolTracker alloc] initWithPool:
Class trackerClass = [QMacAutoReleasePoolTracker class];
#ifdef QT_DEBUG
void *poolFrame = nullptr;
if (__builtin_available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 5.0, *)) {
void *frame;
if (backtrace_from_fp(__builtin_frame_address(0), &frame, 1))
poolFrame = frame;
} else {
static const int maxFrames = 3;
void *callstack[maxFrames];
if (backtrace(callstack, maxFrames) == maxFrames)
poolFrame = callstack[maxFrames - 1];
}
if (poolFrame) {
Dl_info info;
if (dladdr(poolFrame, &info) && info.dli_sname) {
const char *symbolName = info.dli_sname;
if (symbolName[0] == '_') {
int status;
if (char *demangled = abi::__cxa_demangle(info.dli_sname, nullptr, 0, &status))
symbolName = demangled;
}
char *className = nullptr;
asprintf(&className, " ^-- allocated in function: %s", symbolName);
if (Class existingClass = objc_getClass(className))
trackerClass = existingClass;
else
trackerClass = objc_duplicateClass(trackerClass, className, 0);
free(className);
if (symbolName != info.dli_sname)
free((char*)symbolName);
}
}
#endif
[[[trackerClass alloc] initWithPool:
reinterpret_cast<NSAutoreleasePool **>(&pool)] autorelease];
}

View File

@ -59,8 +59,9 @@
},
"bcm_host": {
"export": "",
"headers": ["bcm_host.h"],
"sources": [
"-lbcm_host"
{ "type": "makeSpec", "spec": "BCM_HOST" }
]
},
"dxguid": {

View File

@ -62,7 +62,7 @@ public:
}
QWindow *window;
QPlatformBackingStore *platformBackingStore;
QPlatformBackingStore *platformBackingStore = nullptr;
QScopedPointer<QImage> highDpiBackingstore;
QRegion staticContents;
QSize size;
@ -95,8 +95,6 @@ public:
QBackingStore::QBackingStore(QWindow *window)
: d_ptr(new QBackingStorePrivate(window))
{
d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(window);
d_ptr->platformBackingStore->setBackingStore(this);
}
/*!
@ -131,7 +129,8 @@ void QBackingStore::beginPaint(const QRegion &region)
d_ptr->highDpiBackingstore->devicePixelRatio() != d_ptr->window->devicePixelRatio())
resize(size());
d_ptr->platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window));
QPlatformBackingStore *platformBackingStore = handle();
platformBackingStore->beginPaint(QHighDpi::toNativeLocalRegion(region, d_ptr->window));
// When QtGui is applying a high-dpi scale factor the backing store
// creates a "large" backing store image. This image needs to be
@ -139,7 +138,7 @@ void QBackingStore::beginPaint(const QRegion &region)
// devicePixelRatio. Do this on a separate image instance that shares
// the image data to avoid having the new devicePixelRatio be propagated
// back to the platform plugin.
QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
QPaintDevice *device = platformBackingStore->paintDevice();
if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image) {
QImage *source = static_cast<QImage *>(device);
const bool needsNewImage = d_ptr->highDpiBackingstore.isNull()
@ -168,7 +167,7 @@ void QBackingStore::beginPaint(const QRegion &region)
*/
QPaintDevice *QBackingStore::paintDevice()
{
QPaintDevice *device = d_ptr->platformBackingStore->paintDevice();
QPaintDevice *device = handle()->paintDevice();
if (QHighDpiScaling::isActive() && device->devType() == QInternal::Image)
return d_ptr->highDpiBackingstore.data();
@ -189,7 +188,18 @@ void QBackingStore::endPaint()
if (paintDevice()->paintingActive())
qWarning() << "QBackingStore::endPaint() called with active painter on backingstore paint device";
d_ptr->platformBackingStore->endPaint();
handle()->endPaint();
}
static bool isRasterSurface(QWindow *window)
{
switch (window->surfaceType()) {
case QSurface::RasterSurface:
case QSurface::RasterGLSurface:
return true;
default:
return false;
};
}
/*!
@ -220,6 +230,13 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
return;
}
if (!isRasterSurface(window)) {
qWarning() << "Attempted flush to non-raster surface" << window << "of type" << window->surfaceType()
<< (window->inherits("QWidgetWindow") ? "(consider using Qt::WA_PaintOnScreen to exclude "
"from backingstore sync)" : "");
return;
}
#ifdef QBACKINGSTORE_DEBUG
if (window && window->isTopLevel() && !qt_window_private(window)->receivedExpose) {
qWarning().nospace() << "QBackingStore::flush() called with non-exposed window "
@ -229,7 +246,7 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
Q_ASSERT(window == topLevelWindow || topLevelWindow->isAncestorOf(window, QWindow::ExcludeTransients));
d_ptr->platformBackingStore->flush(window, QHighDpi::toNativeLocalRegion(region, window),
handle()->flush(window, QHighDpi::toNativeLocalRegion(region, window),
QHighDpi::toNativeLocalPosition(offset, window));
}
@ -241,7 +258,7 @@ void QBackingStore::flush(const QRegion &region, QWindow *window, const QPoint &
void QBackingStore::resize(const QSize &size)
{
d_ptr->size = size;
d_ptr->platformBackingStore->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents);
handle()->resize(QHighDpi::toNativePixels(size, d_ptr->window), d_ptr->staticContents);
}
/*!
@ -268,7 +285,7 @@ bool QBackingStore::scroll(const QRegion &area, int dx, int dy)
if (qFloor(nativeDx) != nativeDx || qFloor(nativeDy) != nativeDy)
return false;
return d_ptr->platformBackingStore->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window),
return handle()->scroll(QHighDpi::toNativeLocalRegion(area, d_ptr->window),
nativeDx, nativeDy);
}
@ -349,6 +366,10 @@ void Q_GUI_EXPORT qt_scrollRectInImage(QImage &img, const QRect &rect, const QPo
*/
QPlatformBackingStore *QBackingStore::handle() const
{
if (!d_ptr->platformBackingStore) {
d_ptr->platformBackingStore = QGuiApplicationPrivate::platformIntegration()->createPlatformBackingStore(d_ptr->window);
d_ptr->platformBackingStore->setBackingStore(const_cast<QBackingStore*>(this));
}
return d_ptr->platformBackingStore;
}

View File

@ -1141,7 +1141,8 @@ QTextHtmlImporter::ProcessNodeResult QTextHtmlImporter::processBlockNode()
// ####################
// block.setFloatPosition(node->cssFloat);
if (wsm == QTextHtmlParserNode::WhiteSpacePre) {
if (wsm == QTextHtmlParserNode::WhiteSpacePre
|| wsm == QTextHtmlParserNode::WhiteSpaceNoWrap) {
block.setNonBreakableLines(true);
modifiedBlockFormat = true;
}

View File

@ -1429,8 +1429,8 @@ QT_WARNING_POP
reinterpret_cast<const OS2Table *>(fontData.constData()
+ qFromBigEndian<quint32>(os2TableEntry->offset));
bool italic = qFromBigEndian<quint16>(os2Table->selection) & 1;
bool oblique = qFromBigEndian<quint16>(os2Table->selection) & 128;
bool italic = qFromBigEndian<quint16>(os2Table->selection) & (1 << 0);
bool oblique = qFromBigEndian<quint16>(os2Table->selection) & (1 << 9);
if (italic)
fontEngine->fontDef.style = QFont::StyleItalic;

View File

@ -115,30 +115,33 @@ static FontKeys &fontKeys()
{
static FontKeys result;
if (result.isEmpty()) {
const QSettings fontRegistry(QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
QSettings::NativeFormat);
const QStringList allKeys = fontRegistry.allKeys();
const QString trueType = QStringLiteral("(TrueType)");
const QStringList keys = { QStringLiteral("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"),
QStringLiteral("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts") };
for (const auto key : keys) {
const QSettings fontRegistry(key, QSettings::NativeFormat);
const QStringList allKeys = fontRegistry.allKeys();
const QString trueType = QStringLiteral("(TrueType)");
#if QT_CONFIG(regularexpression)
const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
const QRegularExpression sizeListMatch(QStringLiteral("\\s(\\d+,)+\\d+"));
#else
const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+"));
const QRegExp sizeListMatch(QLatin1String("\\s(\\d+,)+\\d+"));
#endif
Q_ASSERT(sizeListMatch.isValid());
const int size = allKeys.size();
result.reserve(size);
for (int i = 0; i < size; ++i) {
FontKey fontKey;
const QString &registryFontKey = allKeys.at(i);
fontKey.fileName = fontRegistry.value(registryFontKey).toString();
QString realKey = registryFontKey;
realKey.remove(trueType);
realKey.remove(sizeListMatch);
const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&'));
fontKey.fontNames.reserve(fontNames.size());
for (const QStringRef &fontName : fontNames)
fontKey.fontNames.append(fontName.trimmed().toString());
result.append(fontKey);
Q_ASSERT(sizeListMatch.isValid());
const int size = allKeys.size();
result.reserve(result.size() + size);
for (int i = 0; i < size; ++i) {
FontKey fontKey;
const QString &registryFontKey = allKeys.at(i);
fontKey.fileName = fontRegistry.value(registryFontKey).toString();
QString realKey = registryFontKey;
realKey.remove(trueType);
realKey.remove(sizeListMatch);
const auto fontNames = QStringRef(&realKey).trimmed().split(QLatin1Char('&'));
fontKey.fontNames.reserve(fontNames.size());
for (const QStringRef &fontName : fontNames)
fontKey.fontNames.append(fontName.trimmed().toString());
result.append(fontKey);
}
}
}
return result;

View File

@ -269,15 +269,14 @@ struct DeferredDebugHelper
void QCocoaScreen::deliverUpdateRequests()
{
if (!QGuiApplication::instance())
return;
QMacAutoReleasePool pool;
// The CVDisplayLink callback is a notification that it's a good time to produce a new frame.
// Since the callback is delivered on a separate thread we have to marshal it over to the
// main thread, as Qt requires update requests to be delivered there. This needs to happen
// asynchronously, as otherwise we may end up deadlocking if the main thread calls back
// into any of the CVDisplayLink APIs.
if (QThread::currentThread() != QGuiApplication::instance()->thread()) {
if (!NSThread.isMainThread) {
// We're explicitly not using the data of the GCD source to track the pending updates,
// as the data isn't reset to 0 until after the event handler, and also doesn't update
// during the event handler, both of which we need to track late frames.

View File

@ -1513,9 +1513,9 @@ void QCocoaWindow::deliverUpdateRequest()
void QCocoaWindow::requestActivateWindow()
{
NSWindow *window = [m_view window];
[window makeFirstResponder:m_view];
[window makeKeyWindow];
QMacAutoReleasePool pool;
[m_view.window makeFirstResponder:m_view];
[m_view.window makeKeyWindow];
}
QCocoaNSWindow *QCocoaWindow::createNSWindow(bool shouldBePanel)

View File

@ -102,40 +102,6 @@ static QCocoaWindow *toPlatformWindow(NSWindow *window)
return QCocoaScreen::mapToNative(maximizedFrame);
}
#pragma clang diagnostic push
// NSDisableScreenUpdates and NSEnableScreenUpdates are deprecated, but the
// NSAnimationContext API that replaces them doesn't handle the use-case of
// cross-thread screen update synchronization.
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)frameSize
{
Q_ASSERT(toPlatformWindow(window));
qCDebug(lcQpaWindow) << window << "will resize to" << QSizeF::fromCGSize(frameSize)
<< "- disabling screen updates temporarily";
// There may be separate threads rendering to CA layers in this window,
// and if any of them do a swap while the resize is still in progress,
// the visual bounds of that layer will be updated before the visual
// bounds of the window frame, resulting in flickering while resizing.
// To prevent this we disable screen updates for the whole process until
// the resize is complete, which makes the whole thing visually atomic.
NSDisableScreenUpdates();
return frameSize;
}
- (void)windowDidResize:(NSNotification *)notification
{
NSWindow *window = notification.object;
Q_ASSERT(toPlatformWindow(window));
qCDebug(lcQpaWindow) << window << "was resized - re-enabling screen updates";
NSEnableScreenUpdates();
}
#pragma clang diagnostic pop
- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu
{
Q_UNUSED(menu);

View File

@ -63,7 +63,6 @@ QEglFSKmsGbmIntegration::QEglFSKmsGbmIntegration()
#ifndef EGL_EXT_platform_base
typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
#endif
#ifndef EGL_PLATFORM_GBM_KHR

View File

@ -45,6 +45,10 @@
QT_BEGIN_NAMESPACE
#ifndef EGL_EXT_platform_base
typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
#endif
void QEglFSKmsGbmWindow::resetSurface()
{
QEglFSKmsGbmScreen *gbmScreen = static_cast<QEglFSKmsGbmScreen *>(screen());

View File

@ -334,12 +334,8 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (!touchDevice)
return false;
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) {
QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
} else {
if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
}
if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
QWindowSystemInterface::registerTouchDevice(touchDevice);
@ -376,7 +372,6 @@ bool QWindowsContext::initPointer(unsigned integrationOptions)
if (!QWindowsContext::user32dll.supportsPointerApi())
return false;
QWindowsContext::user32dll.enableMouseInPointer(TRUE);
d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
return true;
}
@ -1218,9 +1213,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
case QtWindows::NonClientMouseEvent:
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
else
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
break;
case QtWindows::NonClientPointerEvent:
if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
@ -1246,10 +1242,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
window = window->parent();
if (!window)
return false;
if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
else
if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
else
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
}
break;
case QtWindows::TouchEvent:

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -50,9 +50,6 @@
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
#include "qwindowsscreen.h"
#if QT_CONFIG(draganddrop)
# include "qwindowsdrag.h"
#endif
#include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.h>
@ -78,111 +75,9 @@ enum {
QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD
};
struct PointerTouchEventInfo {
QPointer<QWindow> window;
QList<QWindowSystemInterface::TouchPoint> points;
Qt::KeyboardModifiers modifiers;
};
struct PointerTabletEventInfo {
QPointer<QWindow> window;
QPointF local;
QPointF global;
int device;
int pointerType;
Qt::MouseButtons buttons;
qreal pressure;
int xTilt;
int yTilt;
qreal tangentialPressure;
qreal rotation;
int z;
qint64 uid;
Qt::KeyboardModifiers modifiers;
};
static QQueue<PointerTouchEventInfo> touchEventQueue;
static QQueue<PointerTabletEventInfo> tabletEventQueue;
static void enqueueTouchEvent(QWindow *window,
const QList<QWindowSystemInterface::TouchPoint> &points,
Qt::KeyboardModifiers modifiers)
{
PointerTouchEventInfo eventInfo;
eventInfo.window = window;
eventInfo.points = points;
eventInfo.modifiers = modifiers;
touchEventQueue.enqueue(eventInfo);
}
static void enqueueTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
int device, int pointerType, Qt::MouseButtons buttons, qreal pressure,
int xTilt, int yTilt, qreal tangentialPressure, qreal rotation,
int z, qint64 uid, Qt::KeyboardModifiers modifiers)
{
PointerTabletEventInfo eventInfo;
eventInfo.window = window;
eventInfo.local = local;
eventInfo.global = global;
eventInfo.device = device;
eventInfo.pointerType = pointerType;
eventInfo.buttons = buttons;
eventInfo.pressure = pressure;
eventInfo.xTilt = xTilt;
eventInfo.yTilt = yTilt;
eventInfo.tangentialPressure = tangentialPressure;
eventInfo.rotation = rotation;
eventInfo.z = z;
eventInfo.uid = uid;
eventInfo.modifiers = modifiers;
tabletEventQueue.enqueue(eventInfo);
}
static void flushTouchEvents(QTouchDevice *touchDevice)
{
while (!touchEventQueue.isEmpty()) {
PointerTouchEventInfo eventInfo = touchEventQueue.dequeue();
if (eventInfo.window) {
QWindowSystemInterface::handleTouchEvent(eventInfo.window,
touchDevice,
eventInfo.points,
eventInfo.modifiers);
}
}
}
static void flushTabletEvents()
{
while (!tabletEventQueue.isEmpty()) {
PointerTabletEventInfo eventInfo = tabletEventQueue.dequeue();
if (eventInfo.window) {
QWindowSystemInterface::handleTabletEvent(eventInfo.window,
eventInfo.local,
eventInfo.global,
eventInfo.device,
eventInfo.pointerType,
eventInfo.buttons,
eventInfo.pressure,
eventInfo.xTilt,
eventInfo.yTilt,
eventInfo.tangentialPressure,
eventInfo.rotation,
eventInfo.z,
eventInfo.uid,
eventInfo.modifiers);
}
}
}
bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
{
*result = 0;
// If we are inside the move/resize modal loop, let DefWindowProc() handle it (but process NC button release).
QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
if (msg.message != WM_NCPOINTERUP && platformWindow->testFlag(QWindowsWindow::ResizeMoveActive))
return false;
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
POINTER_INPUT_TYPE pointerType;
@ -191,30 +86,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
return false;
}
m_lastPointerType = pointerType;
// Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow.
if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) {
POINTER_INFO pointerInfo;
if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
qWarning() << "GetPointerInfo() failed:" << qt_error_string();
return false;
}
if (pointerInfo.pointerFlags & (POINTER_FLAG_UP | POINTER_FLAG_DOWN))
return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
return false;
}
switch (pointerType) {
case QT_PT_POINTER:
case QT_PT_MOUSE:
case QT_PT_TOUCHPAD: {
POINTER_INFO pointerInfo;
if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
qWarning() << "GetPointerInfo() failed:" << qt_error_string();
return false;
}
return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
// Let Mouse/TouchPad be handled using legacy messages.
return false;
}
case QT_PT_TOUCH: {
quint32 pointerCount = 0;
@ -290,76 +167,71 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
return false;
}
static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QEvent::Type *eventType, Qt::MouseButton *mouseButton)
namespace {
struct MouseEvent {
QEvent::Type type;
Qt::MouseButton button;
};
} // namespace
static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
{
static const QHash<POINTER_BUTTON_CHANGE_TYPE, Qt::MouseButton> buttonMapping {
{POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton},
{POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton},
{POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton},
{POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton},
{POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton},
{POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton},
{POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1},
{POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1},
{POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2},
{POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2},
};
static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = {
POINTER_CHANGE_FIRSTBUTTON_DOWN,
POINTER_CHANGE_SECONDBUTTON_DOWN,
POINTER_CHANGE_THIRDBUTTON_DOWN,
POINTER_CHANGE_FOURTHBUTTON_DOWN,
POINTER_CHANGE_FIFTHBUTTON_DOWN,
};
static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = {
POINTER_CHANGE_FIRSTBUTTON_UP,
POINTER_CHANGE_SECONDBUTTON_UP,
POINTER_CHANGE_THIRDBUTTON_UP,
POINTER_CHANGE_FOURTHBUTTON_UP,
POINTER_CHANGE_FIFTHBUTTON_UP,
};
if (!eventType || !mouseButton)
return;
const bool nonClient = message == WM_NCPOINTERUPDATE ||
message == WM_NCPOINTERDOWN ||
message == WM_NCPOINTERUP;
if (std::find(std::begin(downChanges),
std::end(downChanges), changeType) < std::end(downChanges)) {
*eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress :
QEvent::MouseButtonPress;
} else if (std::find(std::begin(upChanges),
std::end(upChanges), changeType) < std::end(upChanges)) {
*eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease :
QEvent::MouseButtonRelease;
} else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) {
*eventType = QEvent::Wheel;
} else {
*eventType = nonClient ? QEvent::NonClientAreaMouseMove :
QEvent::MouseMove;
}
*mouseButton = buttonMapping.value(changeType, Qt::NoButton);
return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
}
static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags)
static inline MouseEvent eventFromMsg(const MSG &msg)
{
Qt::MouseButtons result = Qt::NoButton;
if (pointerFlags & POINTER_FLAG_FIRSTBUTTON)
result |= Qt::LeftButton;
if (pointerFlags & POINTER_FLAG_SECONDBUTTON)
result |= Qt::RightButton;
if (pointerFlags & POINTER_FLAG_THIRDBUTTON)
result |= Qt::MiddleButton;
if (pointerFlags & POINTER_FLAG_FOURTHBUTTON)
result |= Qt::XButton1;
if (pointerFlags & POINTER_FLAG_FIFTHBUTTON)
result |= Qt::XButton2;
return result;
switch (msg.message) {
case WM_MOUSEMOVE:
return {QEvent::MouseMove, Qt::NoButton};
case WM_LBUTTONDOWN:
return {QEvent::MouseButtonPress, Qt::LeftButton};
case WM_LBUTTONUP:
return {QEvent::MouseButtonRelease, Qt::LeftButton};
case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
return {QEvent::MouseButtonPress, Qt::LeftButton};
case WM_MBUTTONDOWN:
return {QEvent::MouseButtonPress, Qt::MidButton};
case WM_MBUTTONUP:
return {QEvent::MouseButtonRelease, Qt::MidButton};
case WM_MBUTTONDBLCLK:
return {QEvent::MouseButtonPress, Qt::MidButton};
case WM_RBUTTONDOWN:
return {QEvent::MouseButtonPress, Qt::RightButton};
case WM_RBUTTONUP:
return {QEvent::MouseButtonRelease, Qt::RightButton};
case WM_RBUTTONDBLCLK:
return {QEvent::MouseButtonPress, Qt::RightButton};
case WM_XBUTTONDOWN:
return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
case WM_XBUTTONUP:
return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
case WM_XBUTTONDBLCLK:
return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
case WM_NCMOUSEMOVE:
return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
case WM_NCLBUTTONDOWN:
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
case WM_NCLBUTTONUP:
return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
case WM_NCLBUTTONDBLCLK:
return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
case WM_NCMBUTTONDOWN:
return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
case WM_NCMBUTTONUP:
return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
case WM_NCMBUTTONDBLCLK:
return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
case WM_NCRBUTTONDOWN:
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
case WM_NCRBUTTONUP:
return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
case WM_NCRBUTTONDBLCLK:
return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
default: // WM_MOUSELEAVE
break;
}
return {QEvent::None, Qt::NoButton};
}
static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
@ -419,15 +291,6 @@ static bool isValidWheelReceiver(QWindow *candidate)
return false;
}
static bool isMenuWindow(QWindow *window)
{
if (window)
if (QObject *fo = window->focusObject())
if (fo->inherits("QMenu"))
return true;
return false;
}
static QTouchDevice *createTouchDevice()
{
const int digitizers = GetSystemMetrics(SM_DIGITIZER);
@ -553,71 +416,6 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window,
m_previousCaptureWindow = hasCapture ? window : nullptr;
}
bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType et,
MSG msg, PVOID vPointerInfo)
{
POINTER_INFO *pointerInfo = static_cast<POINTER_INFO *>(vPointerInfo);
const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y);
const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags);
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
switch (msg.message) {
case WM_NCPOINTERDOWN:
case WM_NCPOINTERUP:
case WM_NCPOINTERUPDATE:
case WM_POINTERDOWN:
case WM_POINTERUP:
case WM_POINTERUPDATE: {
QEvent::Type eventType;
Qt::MouseButton button;
getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, &eventType, &button);
if (et & QtWindows::NonClientEventFlag) {
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
keyModifiers, Qt::MouseEventNotSynthesized);
return false; // To allow window dragging, etc.
} else {
handleCaptureRelease(window, currentWindowUnderPointer, hwnd, eventType, mouseButtons);
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
keyModifiers, Qt::MouseEventNotSynthesized);
// The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND
// has go to through DefWindowProc() for resizing to work, so we return false here,
// unless the click was on a menu, as it would mess with menu processing.
return msg.message != WM_POINTERDOWN || isMenuWindow(window);
}
}
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
if (msg.message == WM_POINTERHWHEEL)
delta = -delta;
const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ?
QPoint(delta, 0) : QPoint(0, delta);
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
return true;
}
case WM_POINTERLEAVE:
return true;
}
return false;
}
bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType et,
MSG msg, PVOID vTouchInfo, quint32 count)
@ -653,15 +451,14 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QList<QWindowSystemInterface::TouchPoint> touchPoints;
bool primaryPointer = false;
bool pressRelease = false;
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << showbase
<< __FUNCTION__
<< " message=" << hex << msg.message
<< " count=" << dec << count;
Qt::TouchPointStates allStates = 0;
for (quint32 i = 0; i < count; ++i) {
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << showbase
@ -670,7 +467,13 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
<< " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags;
QWindowSystemInterface::TouchPoint touchPoint;
touchPoint.id = touchInfo[i].pointerInfo.pointerId;
const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
if (id == -1) {
id = m_touchInputIDToTouchPointID.size();
m_touchInputIDToTouchPointID.insert(pointerId, id);
}
touchPoint.id = id;
touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
touchInfo[i].pressure / 1024.0 : 1.0;
if (m_lastTouchPositions.contains(touchPoint.id))
@ -691,32 +494,27 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
touchPoint.state = Qt::TouchPointPressed;
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
pressRelease = true;
} else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
touchPoint.state = Qt::TouchPointReleased;
m_lastTouchPositions.remove(touchPoint.id);
pressRelease = true;
} else {
touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved;
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
}
if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY)
primaryPointer = true;
allStates |= touchPoint.state;
touchPoints.append(touchPoint);
// Avoid getting repeated messages for this frame if there are multiple pointerIds
QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
}
if (primaryPointer && !pressRelease) {
// Postpone event delivery to avoid hanging inside DoDragDrop().
// Only the primary pointer will generate mouse messages.
enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers());
} else {
flushTouchEvents(m_touchDevice);
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
QWindowsKeyMapper::queryKeyboardModifiers());
}
// all touch points released, forget the ids we've seen.
if (allStates == Qt::TouchPointReleased)
m_touchInputIDToTouchPointID.clear();
QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
QWindowsKeyMapper::queryKeyboardModifiers());
return false; // Allow mouse messages to be generated.
}
@ -807,10 +605,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
}
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
// Postpone event delivery to avoid hanging inside DoDragDrop().
enqueueTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
pointerId, keyModifiers);
QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
pressure, xTilt, yTilt, tangentialPressure, rotation, z,
pointerId, keyModifiers);
return false; // Allow mouse messages to be generated.
}
}
@ -835,18 +632,46 @@ static inline bool isMouseEventSynthesizedFromPenOrTouch()
return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE);
}
// Process old-style mouse messages here.
bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
QWindow *currentWindowUnderPointer,
MSG msg,
QPoint globalPos,
Qt::KeyboardModifiers keyModifiers)
{
// Generate enqueued events.
flushTouchEvents(m_touchDevice);
flushTabletEvents();
QWindow *receiver = currentWindowUnderPointer;
if (!isValidWheelReceiver(receiver))
receiver = window;
if (!isValidWheelReceiver(receiver))
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);
QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
return true;
}
// Process legacy mouse messages here.
bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
HWND hwnd,
QtWindows::WindowsEventType et,
MSG msg,
LRESULT *result)
{
*result = 0;
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);
@ -857,46 +682,39 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam);
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
// Handle "press and hold for right-clicking".
// We have to synthesize it here as it only comes from Windows as a fake RMB.
// MS docs say we could use bit 7 from extraInfo to distinguish pen from touch,
// but on the Surface it is set for both. So we use the last pointer type.
if (isMouseEventSynthesizedFromPenOrTouch()) {
if ((msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP)
&& (((m_lastPointerType == QT_PT_PEN)
&& QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents))
|| ((m_lastPointerType == QT_PT_TOUCH)
&& QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)))) {
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::RightButton,
(msg.message == WM_RBUTTONDOWN) ? QEvent::MouseButtonPress
: QEvent::MouseButtonRelease,
keyModifiers, Qt::MouseEventSynthesizedBySystem);
}
// Messages synthesized from touch/pen are only used for flushing queues and press&hold.
return false;
if (et == QtWindows::MouseWheelEvent)
return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
// Windows sends a mouse move with no buttons pressed to signal "Enter"
// when a window is shown over the cursor. Discard the event and only use
// it for generating QEvent::Enter to be consistent with other platforms -
// X11 and macOS.
bool discardEvent = false;
if (msg.message == WM_MOUSEMOVE) {
static QPoint lastMouseMovePos;
if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
discardEvent = true;
lastMouseMovePos = globalPos;
}
if (et == QtWindows::MouseWheelEvent) {
Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
if (isMouseEventSynthesizedFromPenOrTouch()) {
if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
return false;
source = Qt::MouseEventSynthesizedBySystem;
}
if (!isValidWheelReceiver(window))
return true;
const MouseEvent mouseEvent = eventFromMsg(msg);
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 (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
return false; // Allow further event processing
}
if (msg.message == WM_MOUSELEAVE) {
if (window == m_currentWindow) {
QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow;
qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget;
@ -904,14 +722,21 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
} else if (msg.message == WM_MOUSEMOVE) {
QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons);
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
return true;
}
return false;
handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
handleEnterLeave(window, currentWindowUnderPointer, globalPos);
if (!discardEvent && mouseEvent.type != QEvent::None) {
QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons,
mouseEvent.button, mouseEvent.type, keyModifiers, source);
}
// QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
// is sent for unhandled WM_XBUTTONDOWN.
return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
|| QWindowSystemInterface::flushWindowSystemEvents();
}
QT_END_NAMESPACE

View File

@ -1,6 +1,6 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@ -66,19 +66,19 @@ public:
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
private:
bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo);
bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo);
bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
QTouchDevice *m_touchDevice = nullptr;
QHash<int, QPointF> m_lastTouchPositions;
QHash<DWORD, int> m_touchInputIDToTouchPointID;
QPointer<QWindow> m_windowUnderPointer;
QPointer<QWindow> m_currentWindow;
QWindow *m_previousCaptureWindow = nullptr;
bool m_needsEnterOnPointerUpdate = false;
DWORD m_lastPointerType = 0;
};
QT_END_NAMESPACE

View File

@ -511,6 +511,7 @@ public:
QWindow *currentPressWindow = nullptr;
QWindow *currentTargetWindow = nullptr;
bool firstMouseMove = true;
bool resizePending = false;
};
// To be called from the XAML thread
@ -1402,6 +1403,18 @@ void QWinRTScreen::emulateMouseMove(const QPointF &point, MousePositionTransitio
Qt::NoModifier);
}
void QWinRTScreen::setResizePending()
{
Q_D(QWinRTScreen);
d->resizePending = true;
}
bool QWinRTScreen::resizePending() const
{
Q_D(const QWinRTScreen);
return d->resizePending;
}
HRESULT QWinRTScreen::onActivated(ICoreWindow *, IWindowActivatedEventArgs *args)
{
Q_D(QWinRTScreen);
@ -1507,7 +1520,7 @@ HRESULT QWinRTScreen::onRedirectReleased(ICorePointerRedirector *, IPointerEvent
return onPointerUpdated(nullptr, args);
}
HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *)
HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *w, IInspectable *)
{
Q_D(QWinRTScreen);
@ -1527,6 +1540,9 @@ HRESULT QWinRTScreen::onWindowSizeChanged(IApplicationView *, IInspectable *)
QWindowSystemInterface::handleScreenGeometryChange(screen(), geometry(), availableGeometry());
QPlatformScreen::resizeMaximizedWindows();
handleExpose();
// If we "emulate" a resize, w will be nullptr.Checking w shows whether it's a real resize
if (w)
d->resizePending = false;
return S_OK;
}

View File

@ -136,6 +136,9 @@ public:
void emulateMouseMove(const QPointF &point, MousePositionTransition transition);
void setResizePending();
bool resizePending() const;
private:
void handleExpose();

View File

@ -225,7 +225,8 @@ bool QWinRTWindow::isActive() const
bool QWinRTWindow::isExposed() const
{
const bool exposed = isActive();
Q_D(const QWinRTWindow);
const bool exposed = isActive() && !d->screen->resizePending();
return exposed;
}
@ -360,6 +361,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state)
qCDebug(lcQpaWindows) << "Failed to enter full screen mode.";
return;
}
d->screen->setResizePending();
d->state = state;
return;
}
@ -384,6 +386,7 @@ void QWinRTWindow::setWindowState(Qt::WindowStates state)
qCDebug(lcQpaWindows) << "Failed to exit full screen mode.";
return;
}
d->screen->setResizePending();
}
if (d->state & Qt::WindowMinimized || state == Qt::WindowNoState || state == Qt::WindowActive)

View File

@ -8298,49 +8298,57 @@ void QWidgetPrivate::hide_sys()
\endlist
*/
void QWidget::setVisible(bool visible)
{
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden) == !visible)
return;
// Remember that setVisible was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
Q_D(QWidget);
d->setVisible(visible);
}
// This method is called from QWidgetWindow in response to QWindow::setVisible,
// and should match the semantics of QWindow::setVisible. QWidget::setVisible on
// the other hand keeps track of WA_WState_ExplicitShowHide in addition.
void QWidgetPrivate::setVisible(bool visible)
{
Q_Q(QWidget);
if (visible) { // show
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && !testAttribute(Qt::WA_WState_Hidden))
return;
Q_D(QWidget);
// Designer uses a trick to make grabWidget work without showing
if (!isWindow() && parentWidget() && parentWidget()->isVisible()
&& !parentWidget()->testAttribute(Qt::WA_WState_Created))
parentWidget()->window()->d_func()->createRecursively();
if (!q->isWindow() && q->parentWidget() && q->parentWidget()->isVisible()
&& !q->parentWidget()->testAttribute(Qt::WA_WState_Created))
q->parentWidget()->window()->d_func()->createRecursively();
//create toplevels but not children of non-visible parents
QWidget *pw = parentWidget();
if (!testAttribute(Qt::WA_WState_Created)
&& (isWindow() || pw->testAttribute(Qt::WA_WState_Created))) {
create();
QWidget *pw = q->parentWidget();
if (!q->testAttribute(Qt::WA_WState_Created)
&& (q->isWindow() || pw->testAttribute(Qt::WA_WState_Created))) {
q->create();
}
bool wasResized = testAttribute(Qt::WA_Resized);
Qt::WindowStates initialWindowState = windowState();
bool wasResized = q->testAttribute(Qt::WA_Resized);
Qt::WindowStates initialWindowState = q->windowState();
// polish if necessary
ensurePolished();
q->ensurePolished();
// remember that show was called explicitly
setAttribute(Qt::WA_WState_ExplicitShowHide);
// whether we need to inform the parent widget immediately
bool needUpdateGeometry = !isWindow() && testAttribute(Qt::WA_WState_Hidden);
bool needUpdateGeometry = !q->isWindow() && q->testAttribute(Qt::WA_WState_Hidden);
// we are no longer hidden
setAttribute(Qt::WA_WState_Hidden, false);
q->setAttribute(Qt::WA_WState_Hidden, false);
if (needUpdateGeometry)
d->updateGeometry_helper(true);
updateGeometry_helper(true);
// activate our layout before we and our children become visible
if (d->layout)
d->layout->activate();
if (layout)
layout->activate();
if (!isWindow()) {
QWidget *parent = parentWidget();
if (!q->isWindow()) {
QWidget *parent = q->parentWidget();
while (parent && parent->isVisible() && parent->d_func()->layout && !parent->data->in_show) {
parent->d_func()->layout->activate();
if (parent->isWindow())
@ -8353,30 +8361,28 @@ void QWidget::setVisible(bool visible)
// adjust size if necessary
if (!wasResized
&& (isWindow() || !parentWidget()->d_func()->layout)) {
if (isWindow()) {
adjustSize();
if (windowState() != initialWindowState)
setWindowState(initialWindowState);
&& (q->isWindow() || !q->parentWidget()->d_func()->layout)) {
if (q->isWindow()) {
q->adjustSize();
if (q->windowState() != initialWindowState)
q->setWindowState(initialWindowState);
} else {
adjustSize();
q->adjustSize();
}
setAttribute(Qt::WA_Resized, false);
q->setAttribute(Qt::WA_Resized, false);
}
setAttribute(Qt::WA_KeyboardFocusChange, false);
q->setAttribute(Qt::WA_KeyboardFocusChange, false);
if (isWindow() || parentWidget()->isVisible()) {
d->show_helper();
if (q->isWindow() || q->parentWidget()->isVisible()) {
show_helper();
qApp->d_func()->sendSyntheticEnterLeave(this);
qApp->d_func()->sendSyntheticEnterLeave(q);
}
QEvent showToParentEvent(QEvent::ShowToParent);
QApplication::sendEvent(this, &showToParentEvent);
QApplication::sendEvent(q, &showToParentEvent);
} else { // hide
if (testAttribute(Qt::WA_WState_ExplicitShowHide) && testAttribute(Qt::WA_WState_Hidden))
return;
#if 0 // Used to be included in Qt4 for Q_WS_WIN
// reset WS_DISABLED style in a Blocked window
if(isWindow() && testAttribute(Qt::WA_WState_Created)
@ -8387,33 +8393,30 @@ void QWidget::setVisible(bool visible)
SetWindowLong(winId(), GWL_STYLE, dwStyle);
}
#endif
if (QApplicationPrivate::hidden_focus_widget == this)
if (QApplicationPrivate::hidden_focus_widget == q)
QApplicationPrivate::hidden_focus_widget = 0;
Q_D(QWidget);
// hw: The test on getOpaqueRegion() needs to be more intelligent
// currently it doesn't work if the widget is hidden (the region will
// be clipped). The real check should be testing the cached region
// (and dirty flag) directly.
if (!isWindow() && parentWidget()) // && !d->getOpaqueRegion().isEmpty())
parentWidget()->d_func()->setDirtyOpaqueRegion();
if (!q->isWindow() && q->parentWidget()) // && !d->getOpaqueRegion().isEmpty())
q->parentWidget()->d_func()->setDirtyOpaqueRegion();
setAttribute(Qt::WA_WState_Hidden);
setAttribute(Qt::WA_WState_ExplicitShowHide);
if (testAttribute(Qt::WA_WState_Created))
d->hide_helper();
q->setAttribute(Qt::WA_WState_Hidden);
if (q->testAttribute(Qt::WA_WState_Created))
hide_helper();
// invalidate layout similar to updateGeometry()
if (!isWindow() && parentWidget()) {
if (parentWidget()->d_func()->layout)
parentWidget()->d_func()->layout->invalidate();
else if (parentWidget()->isVisible())
QApplication::postEvent(parentWidget(), new QEvent(QEvent::LayoutRequest));
if (!q->isWindow() && q->parentWidget()) {
if (q->parentWidget()->d_func()->layout)
q->parentWidget()->d_func()->layout->invalidate();
else if (q->parentWidget()->isVisible())
QApplication::postEvent(q->parentWidget(), new QEvent(QEvent::LayoutRequest));
}
QEvent hideToParentEvent(QEvent::HideToParent);
QApplication::sendEvent(this, &hideToParentEvent);
QApplication::sendEvent(q, &hideToParentEvent);
}
}

View File

@ -485,6 +485,7 @@ public:
void hide_sys();
void hide_helper();
void _q_showIfNotHidden();
void setVisible(bool);
void setEnabled_helper(bool);
static void adjustFlags(Qt::WindowFlags &flags, QWidget *w = 0);

View File

@ -73,7 +73,7 @@ public:
{
Q_Q(QWidgetWindow);
if (QWidget *widget = q->widget())
widget->setVisible(visible);
QWidgetPrivate::get(widget)->setVisible(visible);
else
QWindowPrivate::setVisible(visible);
}

View File

@ -3064,19 +3064,22 @@ bool QCalendarWidget::eventFilter(QObject *watched, QEvent *event)
{
Q_D(QCalendarWidget);
if (event->type() == QEvent::MouseButtonPress && d->yearEdit->hasFocus()) {
// We can get filtered press events that were intended for Qt Virtual Keyboard's
// input panel (QQuickView), so we have to make sure that the window is indeed a QWidget - no static_cast.
// In addition, as we have a event filter on the whole application we first make sure that the top level widget
// of both this and the watched widget are the same to decide if we should finish the year edition.
QWidget *tlw = window();
QWidget *widget = static_cast<QWidget*>(watched);
//as we have a event filter on the whole application we first make sure that the top level widget
//of both this and the watched widget are the same to decide if we should finish the year edition.
if (widget->window() == tlw) {
QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos());
QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
if (!geom.contains(mousePos)) {
event->accept();
d->_q_yearEditingFinished();
setFocus();
return true;
}
QWidget *widget = qobject_cast<QWidget *>(watched);
if (!widget || widget->window() != tlw)
return QWidget::eventFilter(watched, event);
QPoint mousePos = widget->mapTo(tlw, static_cast<QMouseEvent *>(event)->pos());
QRect geom = QRect(d->yearEdit->mapTo(tlw, QPoint(0, 0)), d->yearEdit->size());
if (!geom.contains(mousePos)) {
event->accept();
d->_q_yearEditingFinished();
setFocus();
return true;
}
}
return QWidget::eventFilter(watched, event);

View File

@ -642,6 +642,8 @@ static bool supportsInternalFboFormat(QOpenGLContext *ctx, int glFormat)
return false;
}
}
#else
Q_UNUSED(glFormat);
#endif
return true;
}

View File

@ -196,6 +196,8 @@ private slots:
void css_linkPseudo();
void css_pageBreaks();
void css_cellPaddings();
void css_whiteSpace_data();
void css_whiteSpace();
void universalSelectors_data();
void universalSelectors();
void screenMedia();
@ -1771,6 +1773,26 @@ void tst_QTextDocumentFragment::css_cellPaddings()
QCOMPARE(cell.format().toTableCellFormat().bottomPadding(), qreal(15));
}
void tst_QTextDocumentFragment::css_whiteSpace_data()
{
QTest::addColumn<QString>("htmlText");
QTest::addColumn<bool>("nowrap");
QTest::newRow("default") << QString("<p>Normal Text</p>") << false;
QTest::newRow("white-space:nowrap") << QString("<p style=white-space:nowrap>Normal Text</p>") << true;
QTest::newRow("white-space:pre") << QString("<p style=white-space:pre>Normal Text</p>") << true;
}
void tst_QTextDocumentFragment::css_whiteSpace()
{
QFETCH(QString, htmlText);
QFETCH(bool, nowrap);
doc->setHtml(htmlText);
QCOMPARE(doc->blockCount(), 1);
QCOMPARE(doc->begin().blockFormat().nonBreakableLines(), nowrap);
}
void tst_QTextDocumentFragment::html_blockLevelDiv()
{
const char html[] = "<div align=right><b>Hello World";

View File

@ -1,3 +0,0 @@
[cursor]
# QTBUG-73545
winrt

View File

@ -53,6 +53,8 @@
#include <QStyleOptionSpinBox>
#include <QStyle>
#include <QProxyStyle>
#include <QScreen>
class SpinBox : public QSpinBox
{
@ -343,6 +345,14 @@ tst_QSpinBox::tst_QSpinBox()
void tst_QSpinBox::init()
{
QLocale::setDefault(QLocale(QLocale::C));
#if QT_CONFIG(cursor)
// Ensure mouse cursor was not left by previous tests where widgets
// will appear, as it could cause events and interfere with the tests.
const QScreen *screen = QGuiApplication::primaryScreen();
const QRect availableGeometry = screen->availableGeometry();
QCursor::setPos(availableGeometry.topLeft());
#endif
}
void tst_QSpinBox::setValue_data()