QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) { if (IDropTargetHelper* dh = QWindowsDrag::instance()->dropHelper()) dh->Drop(pDataObj, reinterpret_cast<POINT*>(&pt), *pdwEffect); qCDebug(lcQpaMime) << __FUNCTION__ << ' ' << m_window << "keys=" << grfKeyState << "pt=" << pt.x << ',' << pt.y; m_lastPoint = QWindowsGeometryHint::mapFromGlobal(m_window, QPoint(pt.x,pt.y)); // grfKeyState does not all ways contain button state in the drop QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(m_lastKeyState); QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const QPlatformDropQtResponse response = QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(), m_lastPoint, translateToQDragDropActions(*pdwEffect)); QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState); m_lastKeyState = grfKeyState; if (response.isAccepted()) { const Qt::DropAction action = response.acceptedAction(); if (action == Qt::MoveAction || action == Qt::TargetMoveAction) { if (action == Qt::MoveAction) m_chosenEffect = DROPEFFECT_MOVE; else m_chosenEffect = DROPEFFECT_COPY; HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); if (hData) { DWORD *moveEffect = reinterpret_cast<DWORD *>(GlobalLock(hData)); *moveEffect = DROPEFFECT_MOVE; GlobalUnlock(hData); STGMEDIUM medium; memset(&medium, 0, sizeof(STGMEDIUM)); medium.tymed = TYMED_HGLOBAL; medium.hGlobal = hData; FORMATETC format; format.cfFormat = CLIPFORMAT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT)); format.tymed = TYMED_HGLOBAL; format.ptd = 0; format.dwAspect = 1; format.lindex = -1; windowsDrag->dropDataObject()->SetData(&format, &medium, true); } } else { m_chosenEffect = translateToWinDragEffects(action); } } else { m_chosenEffect = DROPEFFECT_NONE; } *pdwEffect = m_chosenEffect; windowsDrag->releaseDropDataObject(); return NOERROR; }
QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) { const Qt::DropAction action = translateToQDragDropAction(dwEffect); m_drag->updateAction(action); const qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey(); auto it = m_cursors.constFind(action); // If a custom drag cursor is set, check its cache key to detect changes. if (it == m_cursors.constEnd() || (currentCacheKey && currentCacheKey != it.value().cacheKey)) { createCursors(); it = m_cursors.constFind(action); } if (it != m_cursors.constEnd()) { const CursorEntry &e = it.value(); switch (m_mode) { case MouseDrag: SetCursor(e.cursor->handle()); break; case TouchDrag: if (!m_touchDragWindow) m_touchDragWindow = new QWindowsDragCursorWindow; m_touchDragWindow->setPixmap(e.pixmap); m_touchDragWindow->setFramePosition(QCursor::pos() - e.hotSpot); if (!m_touchDragWindow->isVisible()) m_touchDragWindow->show(); break; } return ResultFromScode(S_OK); } return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS); }
void QWindowsOleDropTarget::handleDrag(QWindow *window, DWORD grfKeyState, const QPoint &point, LPDWORD pdwEffect) { Q_ASSERT(window); m_lastPoint = point; m_lastKeyState = grfKeyState; QWindowsDrag *windowsDrag = QWindowsDrag::instance(); const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); QGuiApplicationPrivate::modifier_buttons = toQtKeyboardModifiers(grfKeyState); QGuiApplicationPrivate::mouse_buttons = toQtMouseButtons(grfKeyState); const QPlatformDragQtResponse response = QWindowSystemInterface::handleDrag(window, windowsDrag->dropData(), m_lastPoint, actions); m_answerRect = response.answerRect(); const Qt::DropAction action = response.acceptedAction(); if (response.isAccepted()) { m_chosenEffect = translateToWinDragEffects(action); } else { m_chosenEffect = DROPEFFECT_NONE; } *pdwEffect = m_chosenEffect; qCDebug(lcQpaMime) << __FUNCTION__ << m_window << windowsDrag->dropData() << " supported actions=" << actions << " mods=" << QGuiApplicationPrivate::modifier_buttons << " mouse=" << QGuiApplicationPrivate::mouse_buttons << " accepted: " << response.isAccepted() << action << m_answerRect << " effect" << *pdwEffect; }
void QWindowsOleDropSource::createCursors() { const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); QList<Qt::DropAction> actions; actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; if (hasPixmap) actions << Qt::IgnoreAction; const QPoint hotSpot = drag->hotSpot(); for (int cnum = 0; cnum < actions.size(); ++cnum) { const Qt::DropAction action = actions.at(cnum); QPixmap cpm = drag->dragCursor(action); if (cpm.isNull()) cpm = m_drag->defaultCursor(action); if (cpm.isNull()) { qWarning("%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action); continue; } int w = cpm.width(); int h = cpm.height(); if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); const int x2 = qMax(pixmap.width() - hotSpot.x(), cpm.width()); const int y1 = qMin(-hotSpot.y(), 0); const int y2 = qMax(pixmap.height() - hotSpot.y(), cpm.height()); w = x2 - x1 + 1; h = y2 - y1 + 1; } const QPoint newHotSpot = hotSpot; QPixmap newCursor(w, h); if (hasPixmap) { newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QRect srcRect = pixmap.rect(); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); p.drawPixmap(pmDest, pixmap, srcRect); p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm); } else { newCursor = cpm; } const int hotX = hasPixmap ? qMax(0,newHotSpot.x()) : 0; const int hotY = hasPixmap ? qMax(0,newHotSpot.y()) : 0; if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newCursor, hotX, hotY)) m_cursors.insert(actions.at(cnum), sysCursor); } if (QWindowsContext::verboseOLE) qDebug("%s %d cursors", __FUNCTION__, m_cursors.size()); }
void QWindowsOleDropSource::createCursors() { const QDrag *drag = m_drag->currentDrag(); const QPixmap pixmap = drag->pixmap(); const bool hasPixmap = !pixmap.isNull(); // Find screen for drag. Could be obtained from QDrag::source(), but that might be a QWidget. const QPlatformScreen *platformScreen = QWindowsContext::instance()->screenManager().screenAtDp(QWindowsCursor::mousePosition()); if (!platformScreen) { if (const QScreen *primaryScreen = QGuiApplication::primaryScreen()) platformScreen = primaryScreen->handle(); } Q_ASSERT(platformScreen); QPlatformCursor *platformCursor = platformScreen->cursor(); qreal pixmapScaleFactor = 1; qreal hotSpotScaleFactor = 1; if (m_mode != TouchDrag) { // Touch drag: pixmap is shown in a separate QWindow, which will be scaled.) hotSpotScaleFactor = QHighDpiScaling::factor(platformScreen); pixmapScaleFactor = hotSpotScaleFactor / pixmap.devicePixelRatio(); } QPixmap scaledPixmap = qFuzzyCompare(pixmapScaleFactor, 1.0) ? pixmap : pixmap.scaled((QSizeF(pixmap.size()) * pixmapScaleFactor).toSize(), Qt::KeepAspectRatio, Qt::SmoothTransformation); scaledPixmap.setDevicePixelRatio(1); Qt::DropAction actions[] = { Qt::MoveAction, Qt::CopyAction, Qt::LinkAction, Qt::IgnoreAction }; int actionCount = int(sizeof(actions) / sizeof(actions[0])); if (!hasPixmap) --actionCount; // No Qt::IgnoreAction unless pixmap const QPoint hotSpot = qFuzzyCompare(hotSpotScaleFactor, 1.0) ? drag->hotSpot() : (QPointF(drag->hotSpot()) * hotSpotScaleFactor).toPoint(); for (int cnum = 0; cnum < actionCount; ++cnum) { const Qt::DropAction action = actions[cnum]; QPixmap cursorPixmap = drag->dragCursor(action); if (cursorPixmap.isNull() && platformCursor) cursorPixmap = static_cast<QWindowsCursor *>(platformCursor)->dragDefaultCursor(action); const qint64 cacheKey = cursorPixmap.cacheKey(); const auto it = m_cursors.find(action); if (it != m_cursors.end() && it.value().cacheKey == cacheKey) continue; if (cursorPixmap.isNull()) { qWarning("%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action); continue; } QPoint newHotSpot(0, 0); QPixmap newPixmap = cursorPixmap; if (hasPixmap) { const int x1 = qMin(-hotSpot.x(), 0); const int x2 = qMax(scaledPixmap.width() - hotSpot.x(), cursorPixmap.width()); const int y1 = qMin(-hotSpot.y(), 0); const int y2 = qMax(scaledPixmap.height() - hotSpot.y(), cursorPixmap.height()); QPixmap newCursor(x2 - x1 + 1, y2 - y1 + 1); newCursor.fill(Qt::transparent); QPainter p(&newCursor); const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); p.drawPixmap(pmDest, scaledPixmap); p.drawPixmap(qMax(0, hotSpot.x()),qMax(0, hotSpot.y()), cursorPixmap); newPixmap = newCursor; newHotSpot = QPoint(qMax(0, hotSpot.x()), qMax(0, hotSpot.y())); } if (const HCURSOR sysCursor = QWindowsCursor::createPixmapCursor(newPixmap, newHotSpot)) { const CursorEntry entry(newPixmap, cacheKey, CursorHandlePtr(new CursorHandle(sysCursor)), newHotSpot); if (it == m_cursors.end()) m_cursors.insert(action, entry); else it.value() = entry; } } #ifndef QT_NO_DEBUG_OUTPUT if (lcQpaMime().isDebugEnabled()) qCDebug(lcQpaMime) << __FUNCTION__ << "pixmap" << pixmap.size() << m_cursors.size() << "cursors:\n" << m_cursors; #endif // !QT_NO_DEBUG_OUTPUT }