Windows: Fix the size of drag cursors in multi-screen setups.

Move QWindowsDrag::defaultCursor() to the per-screen instance
of QWindowsCursor so that the cached default drag cursor pixmaps
are created with the correct size per screen.

Task-number: QTBUG-49511
Change-Id: I02f75ac3b1e5e064325b066ee03e1d5c8a7c7ee8
Reviewed-by: Joerg Bornemann <joerg.bornemann@theqtcompany.com>
This commit is contained in:
Friedemann Kleint 2015-11-19 14:14:37 +01:00
parent 05c8e51d88
commit 07efdb78f0
4 changed files with 111 additions and 105 deletions

View File

@ -692,6 +692,94 @@ void QWindowsCursor::setPos(const QPoint &pos)
SetCursorPos(pos.x() , pos.y());
}
QPixmap QWindowsCursor::dragDefaultCursor(Qt::DropAction action) const
{
switch (action) {
case Qt::CopyAction:
if (m_copyDragCursor.isNull())
m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor, m_screen).pixmap;
return m_copyDragCursor;
case Qt::TargetMoveAction:
case Qt::MoveAction:
if (m_moveDragCursor.isNull())
m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor, m_screen).pixmap;
return m_moveDragCursor;
case Qt::LinkAction:
if (m_linkDragCursor.isNull())
m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor, m_screen).pixmap;
return m_linkDragCursor;
default:
break;
}
static const char * const ignoreDragCursorXpmC[] = {
"24 30 3 1",
". c None",
"a c #000000",
"X c #FFFFFF",
"aa......................",
"aXa.....................",
"aXXa....................",
"aXXXa...................",
"aXXXXa..................",
"aXXXXXa.................",
"aXXXXXXa................",
"aXXXXXXXa...............",
"aXXXXXXXXa..............",
"aXXXXXXXXXa.............",
"aXXXXXXaaaa.............",
"aXXXaXXa................",
"aXXaaXXa................",
"aXa..aXXa...............",
"aa...aXXa...............",
"a.....aXXa..............",
"......aXXa.....XXXX.....",
".......aXXa..XXaaaaXX...",
".......aXXa.XaaaaaaaaX..",
"........aa.XaaaXXXXaaaX.",
"...........XaaaaX..XaaX.",
"..........XaaXaaaX..XaaX",
"..........XaaXXaaaX.XaaX",
"..........XaaX.XaaaXXaaX",
"..........XaaX..XaaaXaaX",
"...........XaaX..XaaaaX.",
"...........XaaaXXXXaaaX.",
"............XaaaaaaaaX..",
".............XXaaaaXX...",
"...............XXXX....."};
if (m_ignoreDragCursor.isNull()) {
#if !defined (Q_OS_WINCE)
HCURSOR cursor = LoadCursor(NULL, IDC_NO);
ICONINFO iconInfo = {0, 0, 0, 0, 0};
GetIconInfo(cursor, &iconInfo);
BITMAP bmColor = {0, 0, 0, 0, 0, 0, 0};
if (iconInfo.hbmColor
&& GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor)
&& bmColor.bmWidth == bmColor.bmWidthBytes / 4) {
const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes;
uchar *colorBits = new uchar[colorBitsLength];
GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits);
const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight,
bmColor.bmWidthBytes, QImage::Format_ARGB32);
m_ignoreDragCursor = QPixmap::fromImage(colorImage);
delete [] colorBits;
} else {
m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC);
}
DeleteObject(iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DestroyCursor(cursor);
#else // !Q_OS_WINCE
m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC);
#endif // !Q_OS_WINCE
}
return m_ignoreDragCursor;
}
/*!
\class QWindowsWindowCursor
\brief Per-Window cursor. Contains a QCursor and manages its associated system

View File

@ -113,6 +113,8 @@ public:
CursorHandlePtr standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor);
CursorHandlePtr pixmapWindowCursor(const QCursor &c);
QPixmap dragDefaultCursor(Qt::DropAction action) const;
private:
typedef QHash<Qt::CursorShape, CursorHandlePtr> StandardCursorCache;
typedef QHash<QWindowsPixmapCursorCacheKey, CursorHandlePtr> PixmapCursorCache;
@ -120,6 +122,11 @@ private:
const QPlatformScreen *const m_screen;
StandardCursorCache m_standardCursorCache;
PixmapCursorCache m_pixmapCursorCache;
mutable QPixmap m_copyDragCursor;
mutable QPixmap m_moveDragCursor;
mutable QPixmap m_linkDragCursor;
mutable QPixmap m_ignoreDragCursor;
};
QT_END_NAMESPACE

View File

@ -271,13 +271,6 @@ QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e)
}
#endif // !QT_NO_DEBUG_STREAM
static qreal dragScaleFactor()
{
const QWindowsScreenManager &screenManager = QWindowsContext::instance()->screenManager();
const QWindowsScreen *screen = screenManager.screenAtDp(QWindowsCursor::mousePosition());
return screen ? QHighDpiScaling::factor(screen) : qreal(1);
}
/*!
\brief Blend custom pixmap with cursors.
*/
@ -288,7 +281,17 @@ void QWindowsOleDropSource::createCursors()
const QPixmap pixmap = drag->pixmap();
const bool hasPixmap = !pixmap.isNull();
const qreal scaleFactor = dragScaleFactor();
// Find screen for drag. Could be obtained from QDrag::source(), but that might be a QWidget.
qreal scaleFactor = 1;
QPlatformCursor *platformCursor = Q_NULLPTR;
if (const QPlatformScreen *platformScreen = QWindowsContext::instance()->screenManager().screenAtDp(QWindowsCursor::mousePosition())) {
scaleFactor = QHighDpiScaling::factor(platformScreen);
platformCursor = platformScreen->cursor();
}
if (!platformCursor && QGuiApplication::primaryScreen())
platformCursor = QGuiApplication::primaryScreen()->handle()->cursor();
const bool scalePixmap = hasPixmap
&& m_mode != TouchDrag // Touch drag: pixmap is shown in a separate QWindow, which will be scaled.
&& (scaleFactor != 1 && scaleFactor != qRound(pixmap.devicePixelRatio()));
@ -306,8 +309,8 @@ void QWindowsOleDropSource::createCursors()
for (int cnum = 0; cnum < actionCount; ++cnum) {
const Qt::DropAction action = actions[cnum];
QPixmap cursorPixmap = drag->dragCursor(action);
if (cursorPixmap.isNull())
cursorPixmap = m_drag->defaultCursor(action);
if (cursorPixmap.isNull() && platformCursor)
cursorPixmap = static_cast<QWindowsCursor *>(platformCursor)->dragDefaultCursor(action);
const qint64 cacheKey = cursorPixmap.cacheKey();
const ActionCursorMapIt it = m_cursors.find(action);
if (it != m_cursors.end() && it.value().cacheKey == cacheKey)
@ -704,94 +707,6 @@ IDropTargetHelper* QWindowsDrag::dropHelper() {
return m_cachedDropTargetHelper;
}
QPixmap QWindowsDrag::defaultCursor(Qt::DropAction action) const
{
switch (action) {
case Qt::CopyAction:
if (m_copyDragCursor.isNull())
m_copyDragCursor = QWindowsCursor::customCursor(Qt::DragCopyCursor).pixmap;
return m_copyDragCursor;
case Qt::TargetMoveAction:
case Qt::MoveAction:
if (m_moveDragCursor.isNull())
m_moveDragCursor = QWindowsCursor::customCursor(Qt::DragMoveCursor).pixmap;
return m_moveDragCursor;
case Qt::LinkAction:
if (m_linkDragCursor.isNull())
m_linkDragCursor = QWindowsCursor::customCursor(Qt::DragLinkCursor).pixmap;
return m_linkDragCursor;
default:
break;
}
static const char * const ignoreDragCursorXpmC[] = {
"24 30 3 1",
". c None",
"a c #000000",
"X c #FFFFFF",
"aa......................",
"aXa.....................",
"aXXa....................",
"aXXXa...................",
"aXXXXa..................",
"aXXXXXa.................",
"aXXXXXXa................",
"aXXXXXXXa...............",
"aXXXXXXXXa..............",
"aXXXXXXXXXa.............",
"aXXXXXXaaaa.............",
"aXXXaXXa................",
"aXXaaXXa................",
"aXa..aXXa...............",
"aa...aXXa...............",
"a.....aXXa..............",
"......aXXa.....XXXX.....",
".......aXXa..XXaaaaXX...",
".......aXXa.XaaaaaaaaX..",
"........aa.XaaaXXXXaaaX.",
"...........XaaaaX..XaaX.",
"..........XaaXaaaX..XaaX",
"..........XaaXXaaaX.XaaX",
"..........XaaX.XaaaXXaaX",
"..........XaaX..XaaaXaaX",
"...........XaaX..XaaaaX.",
"...........XaaaXXXXaaaX.",
"............XaaaaaaaaX..",
".............XXaaaaXX...",
"...............XXXX....."};
if (m_ignoreDragCursor.isNull()) {
#if !defined (Q_OS_WINCE)
HCURSOR cursor = LoadCursor(NULL, IDC_NO);
ICONINFO iconInfo = {0, 0, 0, 0, 0};
GetIconInfo(cursor, &iconInfo);
BITMAP bmColor = {0, 0, 0, 0, 0, 0, 0};
if (iconInfo.hbmColor
&& GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bmColor)
&& bmColor.bmWidth == bmColor.bmWidthBytes / 4) {
const int colorBitsLength = bmColor.bmHeight * bmColor.bmWidthBytes;
uchar *colorBits = new uchar[colorBitsLength];
GetBitmapBits(iconInfo.hbmColor, colorBitsLength, colorBits);
const QImage colorImage(colorBits, bmColor.bmWidth, bmColor.bmHeight,
bmColor.bmWidthBytes, QImage::Format_ARGB32);
m_ignoreDragCursor = QPixmap::fromImage(colorImage);
delete [] colorBits;
} else {
m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC);
}
DeleteObject(iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DestroyCursor(cursor);
#else // !Q_OS_WINCE
m_ignoreDragCursor = QPixmap(ignoreDragCursorXpmC);
#endif // !Q_OS_WINCE
}
return m_ignoreDragCursor;
}
Qt::DropAction QWindowsDrag::drag(QDrag *drag)
{
// TODO: Accessibility handling?

View File

@ -42,6 +42,9 @@
struct IDropTargetHelper;
QT_BEGIN_NAMESPACE
class QPlatformScreen;
class QWindowsDropMimeData : public QWindowsInternalMimeData {
public:
QWindowsDropMimeData() {}
@ -95,18 +98,11 @@ public:
IDropTargetHelper* dropHelper();
QPixmap defaultCursor(Qt::DropAction action) const;
private:
QWindowsDropMimeData m_dropData;
IDataObject *m_dropDataObject;
IDropTargetHelper* m_cachedDropTargetHelper;
mutable QPixmap m_copyDragCursor;
mutable QPixmap m_moveDragCursor;
mutable QPixmap m_linkDragCursor;
mutable QPixmap m_ignoreDragCursor;
};
QT_END_NAMESPACE