QPlatformCursor: Add functions for setting/clearing override cursors
QPA is modeled on the assumption that the cursor is a property of the window and therefore sets the override cursors on all windows. However, on macOS and Windows, the cursor is set per application (or screen). On these platforms, the per window cursor setting needs to be emulated which is a source of bugs especially for override cursors. Add new virtuals to QPlatformCursor allowing to set override cursors which can be implemented by directly setting the cursor on those platforms. Task-number: QTBUG-40122 Task-number: QTBUG-61133 Change-Id: I31d6a927128d22bb1620a8ace35988c0e126236e Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io> Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@qt.io> Reviewed-by: Maurice Kalinowski <maurice.kalinowski@qt.io>bb10
parent
8b23133e50
commit
b05d1c2ebf
|
|
@ -3541,6 +3541,22 @@ static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void applyOverrideCursor(const QList<QScreen *> &screens, const QCursor &c)
|
||||
{
|
||||
for (QScreen *screen : screens) {
|
||||
if (QPlatformCursor *cursor = screen->handle()->cursor())
|
||||
cursor->setOverrideCursor(c);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void clearOverrideCursor(const QList<QScreen *> &screens)
|
||||
{
|
||||
for (QScreen *screen : screens) {
|
||||
if (QPlatformCursor *cursor = screen->handle()->cursor())
|
||||
cursor->clearOverrideCursor();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void applyWindowCursor(const QList<QWindow *> &l)
|
||||
{
|
||||
for (int i = 0; i < l.size(); ++i) {
|
||||
|
|
@ -3585,7 +3601,10 @@ void QGuiApplication::setOverrideCursor(const QCursor &cursor)
|
|||
{
|
||||
CHECK_QAPP_INSTANCE()
|
||||
qGuiApp->d_func()->cursor_list.prepend(cursor);
|
||||
applyCursor(QGuiApplicationPrivate::window_list, cursor);
|
||||
if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
|
||||
applyOverrideCursor(QGuiApplicationPrivate::screen_list, cursor);
|
||||
else
|
||||
applyCursor(QGuiApplicationPrivate::window_list, cursor);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -3607,9 +3626,15 @@ void QGuiApplication::restoreOverrideCursor()
|
|||
qGuiApp->d_func()->cursor_list.removeFirst();
|
||||
if (qGuiApp->d_func()->cursor_list.size() > 0) {
|
||||
QCursor c(qGuiApp->d_func()->cursor_list.value(0));
|
||||
applyCursor(QGuiApplicationPrivate::window_list, c);
|
||||
if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
|
||||
applyOverrideCursor(QGuiApplicationPrivate::screen_list, c);
|
||||
else
|
||||
applyCursor(QGuiApplicationPrivate::window_list, c);
|
||||
} else {
|
||||
applyWindowCursor(QGuiApplicationPrivate::window_list);
|
||||
if (QPlatformCursor::capabilities().testFlag(QPlatformCursor::OverrideCursor))
|
||||
clearOverrideCursor(QGuiApplicationPrivate::screen_list);
|
||||
else
|
||||
applyWindowCursor(QGuiApplicationPrivate::window_list);
|
||||
}
|
||||
}
|
||||
#endif// QT_NO_CURSOR
|
||||
|
|
|
|||
|
|
@ -94,6 +94,17 @@ QT_BEGIN_NAMESPACE
|
|||
\sa QCursor::pos()
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QPlatformCursor::OverrideCursor
|
||||
\since 5.10
|
||||
|
||||
\value OverrideCursor Indicates that the platform implements
|
||||
QPlatformCursor::setOverrideCursor() and
|
||||
QPlatformCursor::clearOverrideCursor().
|
||||
*/
|
||||
|
||||
QPlatformCursor::Capabilities QPlatformCursor::m_capabilities = 0;
|
||||
|
||||
/*!
|
||||
\fn QPlatformCursor::QPlatformCursor()
|
||||
|
||||
|
|
@ -659,4 +670,34 @@ void QPlatformCursorImage::set(const uchar *data, const uchar *mask,
|
|||
\brief Return the cursor's hotspot
|
||||
*/
|
||||
|
||||
#ifndef QT_NO_CURSOR
|
||||
/*!
|
||||
Reimplement this function in subclass to set an override cursor
|
||||
on the associated screen and return true to indicate success.
|
||||
|
||||
This function can be implemented on platforms where the cursor is a
|
||||
property of the application or the screen rather than a property
|
||||
of the window. On these platforms, the OverrideCursor capability
|
||||
should be set.
|
||||
|
||||
\sa QGuiApplication::setOverrideCursor(), Capabilities
|
||||
|
||||
\since 5.10
|
||||
*/
|
||||
void QPlatformCursor::setOverrideCursor(const QCursor &)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Reimplement this function in subclass to clear the override cursor.
|
||||
|
||||
\sa QGuiApplication::clearOverrideCursor(), Capabilities
|
||||
|
||||
\since 5.10
|
||||
*/
|
||||
void QPlatformCursor::clearOverrideCursor()
|
||||
{
|
||||
}
|
||||
#endif // QT_NO_CURSOR
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -78,21 +78,36 @@ private:
|
|||
|
||||
class Q_GUI_EXPORT QPlatformCursor : public QObject {
|
||||
public:
|
||||
enum Capability {
|
||||
OverrideCursor = 0x1
|
||||
};
|
||||
Q_DECLARE_FLAGS(Capabilities, Capability)
|
||||
|
||||
QPlatformCursor();
|
||||
|
||||
// input methods
|
||||
virtual void pointerEvent(const QMouseEvent & event) { Q_UNUSED(event); }
|
||||
#ifndef QT_NO_CURSOR
|
||||
virtual void changeCursor(QCursor * windowCursor, QWindow * window) = 0;
|
||||
#endif
|
||||
virtual void setOverrideCursor(const QCursor &);
|
||||
virtual void clearOverrideCursor();
|
||||
#endif // QT_NO_CURSOR
|
||||
virtual QPoint pos() const;
|
||||
virtual void setPos(const QPoint &pos);
|
||||
|
||||
static Capabilities capabilities() { return m_capabilities; }
|
||||
static void setCapabilities(Capabilities c) { m_capabilities = c; }
|
||||
static void setCapability(Capability c) { m_capabilities.setFlag(c); }
|
||||
|
||||
private:
|
||||
friend void qt_qpa_set_cursor(QWidget * w, bool force);
|
||||
friend class QApplicationPrivate;
|
||||
|
||||
static Capabilities m_capabilities;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QPlatformCursor::Capabilities)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // QPLATFORMCURSOR_H
|
||||
|
|
|
|||
|
|
@ -586,6 +586,13 @@ QWindowsCursor::QWindowsCursor(const QPlatformScreen *screen)
|
|||
Q_UNUSED(dummy)
|
||||
}
|
||||
|
||||
inline CursorHandlePtr QWindowsCursor::cursorHandle(const QCursor &cursor)
|
||||
{
|
||||
return cursor.shape() == Qt::BitmapCursor
|
||||
? pixmapWindowCursor(cursor)
|
||||
: standardWindowCursor(cursor.shape());
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief Set a cursor on a window.
|
||||
|
||||
|
|
@ -603,9 +610,7 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
|
|||
platformWindow->setCursor(CursorHandlePtr(new CursorHandle));
|
||||
return;
|
||||
}
|
||||
const CursorHandlePtr wcursor =
|
||||
cursorIn->shape() == Qt::BitmapCursor ?
|
||||
pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
|
||||
const CursorHandlePtr wcursor = cursorHandle(*cursorIn);
|
||||
if (wcursor->handle()) {
|
||||
platformWindow->setCursor(wcursor);
|
||||
} else {
|
||||
|
|
@ -614,6 +619,25 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
|
|||
}
|
||||
}
|
||||
|
||||
void QWindowsCursor::setOverrideCursor(const QCursor &cursor)
|
||||
{
|
||||
const CursorHandlePtr wcursor = cursorHandle(cursor);
|
||||
if (wcursor->handle()) {
|
||||
m_overriddenCursor = SetCursor(wcursor->handle());
|
||||
} else {
|
||||
qWarning("%s: Unable to obtain system cursor for %d",
|
||||
__FUNCTION__, cursor.shape());
|
||||
}
|
||||
}
|
||||
|
||||
void QWindowsCursor::clearOverrideCursor()
|
||||
{
|
||||
if (m_overriddenCursor) {
|
||||
SetCursor(m_overriddenCursor);
|
||||
m_overriddenCursor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
QPoint QWindowsCursor::mousePosition()
|
||||
{
|
||||
POINT p;
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ public:
|
|||
explicit QWindowsCursor(const QPlatformScreen *screen);
|
||||
|
||||
void changeCursor(QCursor * widgetCursor, QWindow * widget) override;
|
||||
void setOverrideCursor(const QCursor &cursor) override;
|
||||
void clearOverrideCursor() override;
|
||||
|
||||
QPoint pos() const override;
|
||||
void setPos(const QPoint &pos) override;
|
||||
|
||||
|
|
@ -127,6 +130,8 @@ private:
|
|||
typedef QHash<Qt::CursorShape, CursorHandlePtr> StandardCursorCache;
|
||||
typedef QHash<QWindowsPixmapCursorCacheKey, CursorHandlePtr> PixmapCursorCache;
|
||||
|
||||
CursorHandlePtr cursorHandle(const QCursor &c);
|
||||
|
||||
const QPlatformScreen *const m_screen;
|
||||
StandardCursorCache m_standardCursorCache;
|
||||
PixmapCursorCache m_pixmapCursorCache;
|
||||
|
|
@ -135,6 +140,8 @@ private:
|
|||
mutable QPixmap m_moveDragCursor;
|
||||
mutable QPixmap m_linkDragCursor;
|
||||
mutable QPixmap m_ignoreDragCursor;
|
||||
|
||||
HCURSOR m_overriddenCursor = nullptr;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@
|
|||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qhighdpiscaling_p.h>
|
||||
#include <QtGui/qpa/qplatforminputcontextfactory_p.h>
|
||||
#include <QtGui/qpa/qplatformcursor.h>
|
||||
|
||||
#include <QtEventDispatcherSupport/private/qwindowsguieventdispatcher_p.h>
|
||||
|
||||
|
|
@ -242,6 +243,7 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL
|
|||
}
|
||||
|
||||
m_context.initTouch(m_options);
|
||||
QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);
|
||||
}
|
||||
|
||||
QWindowsIntegrationPrivate::~QWindowsIntegrationPrivate()
|
||||
|
|
|
|||
Loading…
Reference in New Issue