QCursor: Associate cursor with screen.

- Introduce cursor() accessor to QPlatformScreen.
- Remove screen member of QPlatformCursor (a
  cursor can be shared by multiple screens
  of a virtual desktop).
- Add QCursor::pos()/ QCursor::setPos() taking
  a QScreen-parameter, use primaryScreen() for
  old overloads.  QCursor::pos() can then query
  the platform cursor for the position and return
  the position even if the mouse position is outside
  the windows owned by the Qt application.
- Fix tests

Reviewed-by: Samuel Rødal <samuel.rodal@nokia.com>

Task-number: QTBUG-22457
Task-number: QTBUG-22565
Task-number: QTBUG-20753
Change-Id: Ia69f37343f95772e934eab1cd806bd54cbdbbe51
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@nokia.com>
bb10
Friedemann Kleint 2012-03-05 14:42:42 +01:00 committed by Qt by Nokia
parent b7915a4d0d
commit b319d44798
34 changed files with 166 additions and 95 deletions

View File

@ -185,10 +185,10 @@ QT_BEGIN_NAMESPACE
*/
/*!
\fn QPoint QCursor::pos()
\fn QPoint QCursor::pos(const QScreen *screen)
Returns the position of the cursor (hot spot) in global screen
coordinates.
Returns the position of the cursor (hot spot) of the \a screen
in global screen coordinates.
You can call QWidget::mapFromGlobal() to translate it to widget
coordinates.
@ -197,10 +197,23 @@ QT_BEGIN_NAMESPACE
*/
/*!
\fn void QCursor::setPos(int x, int y)
\fn QPoint QCursor::pos()
Moves the cursor (hot spot) to the global screen position (\a x,
\a y).
Returns the position of the cursor (hot spot) of
the primary screen in global screen coordinates.
You can call QWidget::mapFromGlobal() to translate it to widget
coordinates.
\sa setPos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal(), QGuiApplication::primaryScreen()
*/
/*!
\fn void QCursor::setPos(QScreen *screen, int x, int y)
Moves the cursor (hot spot) of the \a screen to the global
screen position (\a x, \a y).
You can call QWidget::mapToGlobal() to translate widget
coordinates to global screen coordinates.
@ -208,6 +221,18 @@ QT_BEGIN_NAMESPACE
\sa pos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal()
*/
/*!
\fn void QCursor::setPos(int x, int y)
Moves the cursor (hot spot) of the primary screen
to the global screen position (\a x, \a y).
You can call QWidget::mapToGlobal() to translate widget
coordinates to global screen coordinates.
\sa pos(), QWidget::mapFromGlobal(), QWidget::mapToGlobal(), QGuiApplication::primaryScreen()
*/
/*!
\fn void QCursor::setPos (const QPoint &p)
@ -217,6 +242,15 @@ QT_BEGIN_NAMESPACE
\a p.
*/
/*!
\fn void QCursor::setPos (QScreen *screen,const QPoint &p)
\overload
Moves the cursor (hot spot) to the global screen position of the
\a screen at point \a p.
*/
/*****************************************************************************
QCursor stream functions
*****************************************************************************/

View File

@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE
class QVariant;
class QScreen;
/*
### The fake cursor has to go first with old qdoc.
@ -101,8 +102,11 @@ public:
QPoint hotSpot() const;
static QPoint pos();
static QPoint pos(const QScreen *screen);
static void setPos(int x, int y);
static void setPos(QScreen *screen, int x, int y);
inline static void setPos(const QPoint &p) { setPos(p.x(), p.y()); }
inline static void setPos(QScreen *screen, const QPoint &p) { setPos(screen, p.x(), p.y()); }
#ifdef qdoc
HCURSOR_or_HANDLE handle() const;

View File

@ -40,6 +40,7 @@
****************************************************************************/
#include <qcursor.h>
#include <qscreen.h>
#include <private/qcursor_p.h>
#include <qplatformcursor_qpa.h>
#include <private/qguiapplication_p.h>
@ -110,27 +111,34 @@ void QCursorData::update()
QPoint QCursor::pos()
{
return QCursor::pos(QGuiApplication::primaryScreen());
}
QPoint QCursor::pos(const QScreen *screen)
{
if (screen)
if (const QPlatformCursor *cursor = screen->handle()->cursor())
return cursor->pos();
return QGuiApplicationPrivate::lastCursorPosition.toPoint();
}
void QCursor::setPos(QScreen *screen, int x, int y)
{
if (screen) {
if (QPlatformCursor *cursor = screen->handle()->cursor()) {
const QPoint pos = QPoint(x, y);
// Need to check, since some X servers generate null mouse move
// events, causing looping in applications which call setPos() on
// every mouse move event.
if (pos != cursor->pos())
cursor->setPos(pos);
}
}
}
void QCursor::setPos(int x, int y)
{
QPoint target(x, y);
// Need to check, since some X servers generate null mouse move
// events, causing looping in applications which call setPos() on
// every mouse move event.
//
if (pos() == target)
return;
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
cursor.data()->setPos(target);
}
QCursor::setPos(QGuiApplication::primaryScreen(), x, y);
}
QT_END_NAMESPACE

View File

@ -978,10 +978,9 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo
QMouseEvent ev(type, localPoint, localPoint, globalPoint, button, buttons, e->modifiers);
ev.setTimestamp(e->timestamp);
#ifndef QT_NO_CURSOR
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
for (int i = 0; i < cursors.count(); ++i)
if (cursors.at(i))
cursors.at(i).data()->pointerEvent(ev);
if (const QScreen *screen = window->screen())
if (QPlatformCursor *cursor = screen->handle()->cursor())
cursor->pointerEvent(ev);
#endif
QGuiApplication::sendSpontaneousEvent(window, &ev);
if (!e->synthetic && !ev.isAccepted() && qApp->testAttribute(Qt::AA_SynthesizeTouchForUnhandledMouseEvents)) {
@ -1814,16 +1813,11 @@ void QGuiApplication::changeOverrideCursor(const QCursor &cursor)
#ifndef QT_NO_CURSOR
static void applyCursor(QWindow *w, const QCursor &c)
static inline void applyCursor(QWindow *w, QCursor c)
{
QCursor cc = c;
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
cursor.data()->changeCursor(&cc, w);
}
if (const QScreen *screen = w->screen())
if (QPlatformCursor *cursor = screen->handle()->cursor())
cursor->changeCursor(&c, w);
}
static inline void applyCursor(const QList<QWindow *> &l, const QCursor &c)

View File

@ -43,13 +43,22 @@
#include <QPainter>
#include <QBitmap>
#include <QGuiApplication>
#include <QScreen>
#include <QPlatformScreen>
#include <private/qguiapplication_p.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
QList <QWeakPointer<QPlatformCursor> > QPlatformCursorPrivate::instances;
QList<QPlatformCursor *> QPlatformCursorPrivate::getInstances()
{
QList<QPlatformCursor *> result;
foreach (const QScreen *screen, QGuiApplicationPrivate::screen_list)
if (QPlatformCursor *cursor = screen->handle()->cursor())
result.push_back(cursor);
return result;
}
/*!
\class QPlatformCursor
@ -93,10 +102,8 @@ QList <QWeakPointer<QPlatformCursor> > QPlatformCursorPrivate::instances;
Constructs a QPlatformCursor for the given \a screen.
*/
QPlatformCursor::QPlatformCursor(QPlatformScreen *scr )
: screen(scr)
QPlatformCursor::QPlatformCursor()
{
QPlatformCursorPrivate::instances.append(this);
}
QPoint QPlatformCursor::pos() const

View File

@ -74,13 +74,12 @@ class QPlatformCursor;
class Q_GUI_EXPORT QPlatformCursorPrivate {
public:
static QList<QWeakPointer<QPlatformCursor> > getInstances() { return instances; }
static QList<QWeakPointer<QPlatformCursor> > instances;
static QList<QPlatformCursor *> getInstances();
};
class Q_GUI_EXPORT QPlatformCursor : public QObject {
public:
QPlatformCursor(QPlatformScreen *);
QPlatformCursor();
// input methods
virtual void pointerEvent(const QMouseEvent & event) { Q_UNUSED(event); }
@ -88,11 +87,8 @@ public:
virtual QPoint pos() const;
virtual void setPos(const QPoint &pos);
protected:
QPlatformScreen* screen; // Where to request an update
private:
Q_DECLARE_PRIVATE(QPlatformCursor);
Q_DECLARE_PRIVATE(QPlatformCursor)
friend void qt_qpa_set_cursor(QWidget * w, bool force);
friend class QApplicationPrivate;
};

View File

@ -41,6 +41,7 @@
#include "qplatformscreen_qpa.h"
#include <QtGui/qguiapplication.h>
#include <QtGui/qplatformcursor_qpa.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qplatformscreen_qpa_p.h>
#include <QtGui/qplatformintegration_qpa.h>
@ -250,4 +251,14 @@ QPlatformScreenPageFlipper *QPlatformScreen::pageFlipper() const
return 0;
}
/*!
Reimplement this function in subclass to return the cursor of the screen.
The default implementation returns 0.
*/
QPlatformCursor *QPlatformScreen::cursor() const
{
return 0;
}
QT_END_NAMESPACE

View File

@ -63,6 +63,7 @@ class QPlatformBackingStore;
class QPlatformOpenGLContext;
class QPlatformScreenPrivate;
class QPlatformWindow;
class QPlatformCursor;
class QPlatformScreenPageFlipper;
class QScreen;
class QSurfaceFormat;
@ -103,6 +104,7 @@ public:
virtual QString name() const { return QString(); }
virtual QPlatformScreenPageFlipper *pageFlipper() const;
virtual QPlatformCursor *cursor() const;
protected:
QScopedPointer<QPlatformScreenPrivate> d_ptr;

View File

@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE
class QCocoaCursor : public QPlatformCursor
{
public:
explicit QCocoaCursor(QPlatformScreen *);
QCocoaCursor();
virtual void changeCursor(QCursor * widgetCursor, QWindow * widget);
virtual QPoint pos() const;

View File

@ -47,8 +47,7 @@
QT_BEGIN_NAMESPACE
QCocoaCursor::QCocoaCursor(QPlatformScreen *s) :
QPlatformCursor(s)
QCocoaCursor::QCocoaCursor()
{
// release cursors
QHash<Qt::CursorShape, NSCursor *>::const_iterator i = m_cursors.constBegin();

View File

@ -63,6 +63,7 @@ public:
int depth() const { return m_depth; }
QImage::Format format() const { return m_format; }
QSizeF physicalSize() const { return m_physicalSize; }
QPlatformCursor *cursor() const { return m_cursor; }
public:
NSScreen *m_screen;

View File

@ -79,7 +79,7 @@ QCocoaScreen::QCocoaScreen(int screenIndex)
const qreal inch = 25.4;
m_physicalSize = QSizeF(m_geometry.size()) * inch / dpi;
m_cursor = new QCocoaCursor(this);
m_cursor = new QCocoaCursor;
};
QCocoaScreen::~QCocoaScreen()

View File

@ -45,7 +45,7 @@
QT_BEGIN_NAMESPACE
QDirectFBCursor::QDirectFBCursor(QPlatformScreen *screen)
: QPlatformCursor(screen)
: m_screen(screen)
{
m_image.reset(new QPlatformCursorImage(0, 0, 0, 0, 0, 0));
}
@ -70,7 +70,7 @@ void QDirectFBCursor::changeCursor(QCursor *cursor, QWindow *)
}
DFBResult res;
IDirectFBDisplayLayer *layer = toDfbLayer(screen);
IDirectFBDisplayLayer *layer = toDfbLayer(m_screen);
IDirectFBSurface* surface(QDirectFbConvenience::dfbSurfaceForPlatformPixmap(map.handle()));
res = layer->SetCooperativeLevel(layer, DLSCL_ADMINISTRATIVE);

View File

@ -60,6 +60,7 @@ public:
private:
QScopedPointer<QPlatformCursorImage> m_image;
QPlatformScreen *m_screen;
};
QT_END_NAMESPACE

View File

@ -61,6 +61,7 @@ public:
int depth() const { return m_depth; }
QImage::Format format() const { return m_format; }
QSizeF physicalSize() const { return m_physicalSize; }
QPlatformCursor *cursor() const { return m_cursor.data(); }
// DirectFb helpers
IDirectFBDisplayLayer *dfbLayer() const;

View File

@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
QKmsCursor::QKmsCursor(QKmsScreen *screen)
: QPlatformCursor(screen), m_screen(screen),
: m_screen(screen),
m_graphicsBufferManager(screen->device()->gbmDevice())
{
gbm_bo *bo = gbm_bo_create(m_graphicsBufferManager, 64, 64,

View File

@ -96,6 +96,11 @@ QSizeF QKmsScreen::physicalSize() const
return m_physicalSize;
}
QPlatformCursor *QKmsScreen::cursor() const
{
return m_cursor;
}
GLuint QKmsScreen::framebufferObject() const
{
return m_bufferManager.framebufferObject();

View File

@ -61,6 +61,7 @@ public:
int depth() const;
QImage::Format format() const;
QSizeF physicalSize() const;
QPlatformCursor *cursor() const;
GLuint framebufferObject() const;
quint32 crtcId() const { return m_crtcId; }

View File

@ -72,11 +72,6 @@ Q_GUI_EXPORT HBITMAP qt_createIconMask(const QBitmap &bitmap);
\sa QWindowsWindowCursor
*/
QWindowsCursor::QWindowsCursor(QPlatformScreen *s) :
QPlatformCursor(s)
{
}
HCURSOR QWindowsCursor::createPixmapCursor(const QPixmap &pixmap, int hotX, int hotY)
{
HCURSOR cur = 0;

View File

@ -70,7 +70,7 @@ private:
class QWindowsCursor : public QPlatformCursor
{
public:
explicit QWindowsCursor(QPlatformScreen *);
QWindowsCursor() {}
virtual void changeCursor(QCursor * widgetCursor, QWindow * widget);
virtual QPoint pos() const { return mousePosition(); }

View File

@ -147,6 +147,14 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
return dbg;
}
// Return the cursor to be shared by all screens (virtual desktop).
static inline QSharedPointer<QWindowsCursor> sharedCursor()
{
if (const QScreen *primaryScreen = QGuiApplication::primaryScreen())
return static_cast<const QWindowsScreen *>(primaryScreen->handle())->windowsCursor();
return QSharedPointer<QWindowsCursor>(new QWindowsCursor);
}
/*!
\class QWindowsScreen
\brief Windows screen.
@ -155,7 +163,7 @@ static QDebug operator<<(QDebug dbg, const QWindowsScreenData &d)
*/
QWindowsScreen::QWindowsScreen(const QWindowsScreenData &data) :
m_data(data), m_cursor(this)
m_data(data), m_cursor(sharedCursor())
{
}

View File

@ -46,6 +46,7 @@
#include <QtCore/QList>
#include <QtCore/QPair>
#include <QtCore/QSharedPointer>
#include <QtGui/QPlatformScreen>
QT_BEGIN_NAMESPACE
@ -74,6 +75,8 @@ struct QWindowsScreenData
class QWindowsScreen : public QPlatformScreen
{
public:
typedef QSharedPointer<QWindowsCursor> WindowsCursorPtr;
explicit QWindowsScreen(const QWindowsScreenData &data);
static QWindowsScreen *screenOf(const QWindow *w = 0);
@ -98,14 +101,14 @@ public:
inline void handleChanges(const QWindowsScreenData &newData);
const QWindowsCursor &cursor() const { return m_cursor; }
QWindowsCursor &cursor() { return m_cursor; }
QPlatformCursor *cursor() const { return m_cursor.data(); }
const WindowsCursorPtr &windowsCursor() const { return m_cursor; }
const QWindowsScreenData &data() const { return m_data; }
private:
QWindowsScreenData m_data;
QWindowsCursor m_cursor;
const WindowsCursorPtr m_cursor;
};
class QWindowsScreenManager

View File

@ -618,7 +618,7 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
m_windowState(aWindow->windowState()),
m_opacity(1.0),
m_mouseGrab(false),
m_cursor(QWindowsScreen::screenOf(aWindow)->cursor().standardWindowCursor()),
m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
m_dropTarget(0),
m_savedStyle(0)
{

View File

@ -261,7 +261,7 @@ static const char * const cursorNames[] = {
};
QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
: QXcbObject(conn), QPlatformCursor(screen), m_screen(screen)
: QXcbObject(conn), m_screen(screen)
{
if (cursorCount++)
return;

View File

@ -237,6 +237,11 @@ QSizeF QXcbScreen::physicalSize() const
return QSizeF(m_screen->width_in_millimeters, m_screen->height_in_millimeters);
}
QPlatformCursor *QXcbScreen::cursor() const
{
return m_cursor;
}
int QXcbScreen::screenNumber() const
{
return m_number;

View File

@ -68,6 +68,7 @@ public:
int depth() const;
QImage::Format format() const;
QSizeF physicalSize() const;
QPlatformCursor *cursor() const;
int screenNumber() const;

View File

@ -52,8 +52,7 @@
QT_BEGIN_NAMESPACE
QXlibCursor::QXlibCursor(QXlibScreen *screen)
: QPlatformCursor(screen)
QXlibCursor::QXlibCursor(QXlibScreen *screen) : m_screen(screen)
{
}
@ -191,9 +190,4 @@ Cursor QXlibCursor::createCursorShape(int cshape)
return cursor;
}
QXlibScreen * QXlibCursor::testLiteScreen() const
{
return static_cast<QXlibScreen *>(screen);
}
QT_END_NAMESPACE

View File

@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
class QXlibCursor : QPlatformCursor
class QXlibCursor : public QPlatformCursor
{
public:
QXlibCursor(QXlibScreen *screen);
@ -59,8 +59,9 @@ private:
Cursor createCursorBitmap(QCursor * cursor);
Cursor createCursorShape(int cshape);
QXlibScreen *testLiteScreen() const;
QXlibScreen *testLiteScreen() const { return m_screen; }
QMap<int, Cursor> cursorMap;
QXlibScreen *m_screen;
};
QT_END_NAMESPACE

View File

@ -241,6 +241,11 @@ QXlibScreen::~QXlibScreen()
delete mDisplay;
}
QPlatformCursor *QXlibScreen::cursor() const
{
return mCursor;
}
Window QXlibScreen::rootWindow()
{
return RootWindow(mDisplay->nativeDisplay(), mScreen);

View File

@ -63,6 +63,7 @@ public:
int depth() const { return mDepth; }
QImage::Format format() const { return mFormat; }
QSizeF physicalSize() const { return mPhysicalSize; }
QPlatformCursor *cursor() const;
Window rootWindow();
unsigned long blackPixel();

View File

@ -905,16 +905,12 @@ void QWidgetPrivate::setModal_sys()
}
#ifndef QT_NO_CURSOR
static void applyCursor(QWidget *w, const QCursor &c)
static inline void applyCursor(QWidget *w, QCursor c)
{
QCursor cc = c;
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
int cursorCount = cursors.count();
for (int i = 0; i < cursorCount; ++i) {
const QWeakPointer<QPlatformCursor> &cursor(cursors.at(i));
if (cursor)
cursor.data()->changeCursor(&cc, w->window()->windowHandle());
}
if (QWindow *window = w->windowHandle())
if (const QScreen *screen = window->screen())
if (QPlatformCursor *cursor = screen->handle()->cursor())
cursor->changeCursor(&c, window);
}
void qt_qpa_set_cursor(QWidget *w, bool force)

View File

@ -4338,9 +4338,16 @@ void tst_QGraphicsView::task255529_transformationAnchorMouseAndViewportMargins()
QPointF newMouseScenePos = view.mapToScene(mouseViewPos);
qreal slack = 1;
QEXPECT_FAIL("", "QTBUG-22455", Abort);
QVERIFY(qAbs(newMouseScenePos.x() - mouseScenePos.x()) < slack);
QVERIFY(qAbs(newMouseScenePos.y() - mouseScenePos.y()) < slack);
const qreal dx = qAbs(newMouseScenePos.x() - mouseScenePos.x());
const qreal dy = qAbs(newMouseScenePos.y() - mouseScenePos.y());
const QByteArray message = QString::fromLatin1("QTBUG-22455, distance: dx=%1, dy=%2 slack=%3 (%4).").
arg(dx).arg(dy).arg(slack).arg(qApp->style()->metaObject()->className()).toLocal8Bit();
// This is highly unstable (observed to pass on Windows and some Linux configurations).
#ifdef Q_OS_MAC
QEXPECT_FAIL("", message.constData(), Abort);
#endif
QVERIFY2(dx < slack && dy < slack, message.constData());
#endif
}

View File

@ -1158,9 +1158,6 @@ void tst_QGraphicsWidget::initStyleOption()
QCOMPARE(hasFocus, focus);
bool isUnderMouse = option.state & QStyle::State_MouseOver;
#ifndef Q_OS_WINCE
# if !defined(Q_OS_MAC) && !defined(Q_OS_WIN)
QEXPECT_FAIL("all", "QTBUG-22457", Abort);
# endif
QCOMPARE(isUnderMouse, underMouse);
#endif
// if (layoutDirection != Qt::LeftToRight)

View File

@ -562,9 +562,6 @@ void tst_QMenu::tearOff()
QTest::mouseClick(menu, Qt::LeftButton, 0, QPoint(3, 3), 10);
QTest::qWait(100);
#ifndef Q_OS_MAC
QEXPECT_FAIL("", "QTBUG-22565", Abort);
#endif
QVERIFY(menu->isTearOffMenuVisible());
QPointer<QMenu> torn = 0;
foreach (QWidget *w, QApplication::allWidgets()) {
@ -783,9 +780,6 @@ void tst_QMenu::task258920_mouseBorder()
#ifdef Q_OS_WINCE_WM
QSKIP("Mouse move related signals for Windows Mobile unavailable");
#endif
// ### fixme: Check platforms
QSKIP("QTBUG-20753 QCursor::setPos() / QTest::mouseMove() doesn't work on qpa");
Menu258920 menu;
// For styles which inherit from QWindowsStyle, styleHint(QStyle::SH_Menu_MouseTracking) is true.
menu.setMouseTracking(true);