Windows QPA: Move the touch types API from platformheaders into QtGui

Change TouchWindowTouchType(s) to be (global) property of
QGuiApplication's native Windows interface since it does not make
sense to set it per window.

It appears the previous code setting the types per Window has never
worked since registerTouchWindow() bailed out due to the checks for
the flags TouchRegistered and IsTouchWindow() (setting in
HCBT_CREATEWND). In addition, registering windows for touch after
plugging in a device would not observe the setting.

Move the checks around to make this work.

Task-number: QTBUG-41433
Task-number: QTBUG-48849
Task-number: QTBUG-83252
Change-Id: I4306fdf13208f6eef22655875f3bd1769270e617
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
This commit is contained in:
Friedemann Kleint 2020-07-22 06:29:20 +02:00
parent 034427a45a
commit ac98b6e4ea
10 changed files with 87 additions and 75 deletions

View File

@ -382,6 +382,17 @@ struct Q_GUI_EXPORT QWindowsApplication
AlwaysActivateWindow AlwaysActivateWindow
}; };
enum TouchWindowTouchType {
NormalTouch = 0x00000000,
FineTouch = 0x00000001,
WantPalmTouch = 0x00000002
};
Q_DECLARE_FLAGS(TouchWindowTouchTypes, TouchWindowTouchType)
virtual void setTouchWindowTouchType(TouchWindowTouchTypes type) = 0;
virtual TouchWindowTouchTypes touchWindowTouchType() const = 0;
virtual WindowActivationBehavior windowActivationBehavior() const = 0; virtual WindowActivationBehavior windowActivationBehavior() const = 0;
virtual void setWindowActivationBehavior(WindowActivationBehavior behavior) = 0; virtual void setWindowActivationBehavior(WindowActivationBehavior behavior) = 0;
@ -394,6 +405,10 @@ struct Q_GUI_EXPORT QWindowsApplication
} // QPlatformInterface::Private } // QPlatformInterface::Private
#if defined(Q_OS_WIN)
Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformInterface::Private::QWindowsApplication::TouchWindowTouchTypes)
#endif
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QGUIAPPLICATION_P_H #endif // QGUIAPPLICATION_P_H

View File

@ -41,36 +41,6 @@
version it was developed against. version it was developed against.
*/ */
/*!
\enum QWindowsWindowFunctions::TouchWindowTouchType
This enum represents the supported TouchWindow touch flags for RegisterTouchWindow().
\value NormalTouch
\value FineTouch
\value WantPalmTouch
*/
/*!
\typedef QWindowsWindowFunctions::SetTouchWindowTouchType
This is the typedef for the function returned by QGuiApplication::platformFunction when passed setTouchWindowTouchTypeIdentifier.
*/
/*!
\fn QByteArray QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier()
This function returns the bytearray that can be used to query
QGuiApplication::platformFunction to retrieve the SetTouchWindowTouchType function.
*/
/*!
\fn void QWindowsWindowFunctions::setTouchWindowTouchType(QWindow *window, TouchWindowTouchTypes type)
This is a convenience function that can be used directly instead of resolving the function pointer.
\a window and \a type will be relayed to the function retrieved by QGuiApplication
*/
/*! /*!
\typedef QWindowsWindowFunctions::SetHasBorderInFullScreen \typedef QWindowsWindowFunctions::SetHasBorderInFullScreen

View File

@ -60,24 +60,6 @@ class QWindow;
class QWindowsWindowFunctions { class QWindowsWindowFunctions {
public: public:
enum TouchWindowTouchType {
NormalTouch = 0x00000000,
FineTouch = 0x00000001,
WantPalmTouch = 0x00000002
};
Q_DECLARE_FLAGS(TouchWindowTouchTypes, TouchWindowTouchType)
typedef void (*SetTouchWindowTouchType)(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchType);
static const QByteArray setTouchWindowTouchTypeIdentifier() { return QByteArrayLiteral("WindowsSetTouchWindowTouchType"); }
static void setTouchWindowTouchType(QWindow *window, TouchWindowTouchTypes type)
{
SetTouchWindowTouchType func = reinterpret_cast<SetTouchWindowTouchType>(QGuiApplication::platformFunction(setTouchWindowTouchTypeIdentifier()));
if (func)
func(window, type);
}
typedef void (*SetHasBorderInFullScreen)(QWindow *window, bool border); typedef void (*SetHasBorderInFullScreen)(QWindow *window, bool border);
static const QByteArray setHasBorderInFullScreenIdentifier() { return QByteArrayLiteral("WindowsSetHasBorderInFullScreen"); } static const QByteArray setHasBorderInFullScreenIdentifier() { return QByteArrayLiteral("WindowsSetHasBorderInFullScreen"); }
static void setHasBorderInFullScreen(QWindow *window, bool border) static void setHasBorderInFullScreen(QWindow *window, bool border)
@ -98,8 +80,6 @@ public:
}; };
Q_DECLARE_OPERATORS_FOR_FLAGS(QWindowsWindowFunctions::TouchWindowTouchTypes)
QT_END_NAMESPACE QT_END_NAMESPACE
#endif // QWINDOWSWINDOWFUNCTIONS_H #endif // QWINDOWSWINDOWFUNCTIONS_H

View File

@ -45,6 +45,20 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
void QWindowsApplication::setTouchWindowTouchType(QWindowsApplication::TouchWindowTouchTypes type)
{
if (m_touchWindowTouchTypes == type)
return;
m_touchWindowTouchTypes = type;
if (auto ctx = QWindowsContext::instance())
ctx->registerTouchWindows();
}
QWindowsApplication::TouchWindowTouchTypes QWindowsApplication::touchWindowTouchType() const
{
return m_touchWindowTouchTypes;
}
QWindowsApplication::WindowActivationBehavior QWindowsApplication::windowActivationBehavior() const QWindowsApplication::WindowActivationBehavior QWindowsApplication::windowActivationBehavior() const
{ {
return m_windowActivationBehavior; return m_windowActivationBehavior;

View File

@ -47,6 +47,9 @@ QT_BEGIN_NAMESPACE
class QWindowsApplication : public QPlatformInterface::Private::QWindowsApplication class QWindowsApplication : public QPlatformInterface::Private::QWindowsApplication
{ {
public: public:
void setTouchWindowTouchType(TouchWindowTouchTypes type) override;
TouchWindowTouchTypes touchWindowTouchType() const override;
WindowActivationBehavior windowActivationBehavior() const override; WindowActivationBehavior windowActivationBehavior() const override;
void setWindowActivationBehavior(WindowActivationBehavior behavior) override; void setWindowActivationBehavior(WindowActivationBehavior behavior) override;
@ -57,6 +60,7 @@ public:
private: private:
WindowActivationBehavior m_windowActivationBehavior = DefaultActivateWindow; WindowActivationBehavior m_windowActivationBehavior = DefaultActivateWindow;
TouchWindowTouchTypes m_touchWindowTouchTypes = NormalTouch;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -366,12 +366,18 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
d->m_systemInfo |= QWindowsContext::SI_SupportsTouch; d->m_systemInfo |= QWindowsContext::SI_SupportsTouch;
// A touch device was plugged while the app is running. Register all windows for touch. // A touch device was plugged while the app is running. Register all windows for touch.
if (QGuiApplicationPrivate::is_app_running) { registerTouchWindows();
return true;
}
void QWindowsContext::registerTouchWindows()
{
if (QGuiApplicationPrivate::is_app_running
&& (d->m_systemInfo & QWindowsContext::SI_SupportsTouch) != 0) {
for (QWindowsWindow *w : qAsConst(d->m_windows)) for (QWindowsWindow *w : qAsConst(d->m_windows))
w->registerTouchWindow(); w->registerTouchWindow();
} }
return true;
} }
bool QWindowsContext::initTablet() bool QWindowsContext::initTablet()

View File

@ -173,6 +173,7 @@ public:
bool initTouch(); bool initTouch();
bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only. bool initTouch(unsigned integrationOptions); // For calls from QWindowsIntegration::QWindowsIntegration() only.
void registerTouchWindows();
bool initTablet(); bool initTablet();
bool initPointer(unsigned integrationOptions); bool initPointer(unsigned integrationOptions);
bool disposeTablet(); bool disposeTablet();

View File

@ -258,8 +258,6 @@ QFont QWindowsNativeInterface::logFontToQFont(const void *logFont, int verticalD
QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const QFunctionPointer QWindowsNativeInterface::platformFunction(const QByteArray &function) const
{ {
if (function == QWindowsWindowFunctions::setTouchWindowTouchTypeIdentifier())
return QFunctionPointer(QWindowsWindow::setTouchWindowTouchTypeStatic);
if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier()) if (function == QWindowsWindowFunctions::setHasBorderInFullScreenIdentifier())
return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic); return QFunctionPointer(QWindowsWindow::setHasBorderInFullScreenStatic);
if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier()) if (function == QWindowsWindowFunctions::setHasBorderInFullScreenDefaultIdentifier())

View File

@ -1128,6 +1128,20 @@ QMargins QWindowsBaseWindow::frameMargins_sys() const
return QWindowsGeometryHint::frame(handle(), style(), exStyle()); return QWindowsGeometryHint::frame(handle(), style(), exStyle());
} }
std::optional<QWindowsBaseWindow::TouchWindowTouchTypes>
QWindowsBaseWindow::touchWindowTouchTypes_sys() const
{
ULONG touchFlags = 0;
if (IsTouchWindow(handle(), &touchFlags) == FALSE)
return {};
TouchWindowTouchTypes result;
if ((touchFlags & TWF_FINETOUCH) != 0)
result.setFlag(TouchWindowTouchType::FineTouch);
if ((touchFlags & TWF_WANTPALM) != 0)
result.setFlag(TouchWindowTouchType::WantPalmTouch);
return result;
}
void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows. void QWindowsBaseWindow::hide_sys() // Normal hide, do not activate other windows.
{ {
SetWindowPos(handle(), nullptr , 0, 0, 0, 0, SetWindowPos(handle(), nullptr , 0, 0, 0, 0,
@ -1345,7 +1359,11 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const QWindowsWindowData &data)
#endif #endif
updateDropSite(window()->isTopLevel()); updateDropSite(window()->isTopLevel());
// Register touch unless if the flags are already set by a hook
// such as HCBT_CREATEWND
if (!touchWindowTouchTypes_sys().has_value())
registerTouchWindow(); registerTouchWindow();
const qreal opacity = qt_window_private(aWindow)->opacity; const qreal opacity = qt_window_private(aWindow)->opacity;
if (!qFuzzyCompare(opacity, qreal(1.0))) if (!qFuzzyCompare(opacity, qreal(1.0)))
setOpacity(opacity); setOpacity(opacity);
@ -3040,28 +3058,28 @@ void QWindowsWindow::invalidateSurface()
#endif // QT_NO_OPENGL #endif // QT_NO_OPENGL
} }
void QWindowsWindow::setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes) void QWindowsWindow::registerTouchWindow()
{ {
if (!window->handle()) if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) == 0)
return; return;
static_cast<QWindowsWindow *>(window->handle())->registerTouchWindow(touchTypes);
}
void QWindowsWindow::registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes) // Initially register or re-register to change the flags
{ const auto touchTypes = QWindowsIntegration::instance()->touchWindowTouchType();
if ((QWindowsContext::instance()->systemInfo() & QWindowsContext::SI_SupportsTouch) if (testFlag(TouchRegistered)) {
&& !testFlag(TouchRegistered)) { const auto currentTouchTypes = touchWindowTouchTypes_sys();
ULONG touchFlags = 0; if (currentTouchTypes.has_value() && currentTouchTypes.value() == touchTypes)
const bool ret = IsTouchWindow(m_data.hwnd, &touchFlags);
// Return if it is not a touch window or the flags are already set by a hook
// such as HCBT_CREATEWND
if (ret || touchFlags != 0)
return; return;
if (RegisterTouchWindow(m_data.hwnd, ULONG(touchTypes))) }
ULONG touchFlags = 0;
if (touchTypes.testFlag(TouchWindowTouchType::FineTouch))
touchFlags |= TWF_FINETOUCH;
if (touchTypes.testFlag(TouchWindowTouchType::WantPalmTouch))
touchFlags |= TWF_WANTPALM;
if (RegisterTouchWindow(m_data.hwnd, touchFlags))
setFlag(TouchRegistered); setFlag(TouchRegistered);
else else
qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName())); qErrnoWarning("RegisterTouchWindow() failed for window '%s'.", qPrintable(window()->objectName()));
}
} }
void QWindowsWindow::aboutToMakeCurrent() void QWindowsWindow::aboutToMakeCurrent()

View File

@ -42,6 +42,7 @@
#include <QtCore/qt_windows.h> #include <QtCore/qt_windows.h>
#include <QtCore/qpointer.h> #include <QtCore/qpointer.h>
#include "qwindowsapplication.h"
#include "qwindowscursor.h" #include "qwindowscursor.h"
#include <qpa/qplatformwindow.h> #include <qpa/qplatformwindow.h>
@ -51,6 +52,8 @@
#include "qwindowsvulkaninstance.h" #include "qwindowsvulkaninstance.h"
#endif #endif
#include <optional>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QWindowsOleDropTarget; class QWindowsOleDropTarget;
@ -125,6 +128,9 @@ class QWindowsBaseWindow : public QPlatformWindow
{ {
Q_DISABLE_COPY_MOVE(QWindowsBaseWindow) Q_DISABLE_COPY_MOVE(QWindowsBaseWindow)
public: public:
using TouchWindowTouchType = QPlatformInterface::Private::QWindowsApplication::TouchWindowTouchType;
using TouchWindowTouchTypes = QPlatformInterface::Private::QWindowsApplication::TouchWindowTouchTypes;
explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {} explicit QWindowsBaseWindow(QWindow *window) : QPlatformWindow(window) {}
WId winId() const override { return WId(handle()); } WId winId() const override { return WId(handle()); }
@ -153,6 +159,7 @@ protected:
QRect geometry_sys() const; QRect geometry_sys() const;
void setGeometry_sys(const QRect &rect) const; void setGeometry_sys(const QRect &rect) const;
QMargins frameMargins_sys() const; QMargins frameMargins_sys() const;
std::optional<TouchWindowTouchTypes> touchWindowTouchTypes_sys() const;
void hide_sys(); void hide_sys();
void raise_sys(); void raise_sys();
void lower_sys(); void lower_sys();
@ -348,8 +355,7 @@ public:
enum ScreenChangeMode { FromGeometryChange, FromDpiChange }; enum ScreenChangeMode { FromGeometryChange, FromDpiChange };
void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange); void checkForScreenChanged(ScreenChangeMode mode = FromGeometryChange);
static void setTouchWindowTouchTypeStatic(QWindow *window, QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes); void registerTouchWindow();
void registerTouchWindow(QWindowsWindowFunctions::TouchWindowTouchTypes touchTypes = QWindowsWindowFunctions::NormalTouch);
static void setHasBorderInFullScreenStatic(QWindow *window, bool border); static void setHasBorderInFullScreenStatic(QWindow *window, bool border);
static void setHasBorderInFullScreenDefault(bool border); static void setHasBorderInFullScreenDefault(bool border);
void setHasBorderInFullScreen(bool border); void setHasBorderInFullScreen(bool border);