4#include <QtCore/qt_windows.h>
8#if QT_CONFIG(clipboard)
18#include <QtGui/qevent.h>
19#include <QtGui/qpixmap.h>
20#include <QtGui/qpainter.h>
21#include <QtGui/qrasterwindow.h>
22#include <QtGui/qguiapplication.h>
23#include <qpa/qwindowsysteminterface_p.h>
24#include <QtGui/private/qdnd_p.h>
25#include <QtGui/private/qguiapplication_p.h>
26#include <QtGui/private/qhighdpiscaling_p.h>
28#include <QtCore/qdebug.h>
29#include <QtCore/qbuffer.h>
30#include <QtCore/qpoint.h>
31#include <QtCore/qpointer.h>
32#include <QtCore/private/qcomobject_p.h>
68 windowFormat.setAlphaBufferSize(8);
82 qCDebug(lcQpaMime) << __FUNCTION__ <<
p.cacheKey() << newSize;
84 if (oldSize != newSize) {
87 newSize /=
qRound(pixDevicePixelRatio);
113 if (pdwEffects & DROPEFFECT_LINK)
115 if (pdwEffects & DROPEFFECT_COPY)
117 if (pdwEffects & DROPEFFECT_MOVE)
124 if (pdwEffect & DROPEFFECT_LINK)
126 if (pdwEffect & DROPEFFECT_COPY)
128 if (pdwEffect & DROPEFFECT_MOVE)
135 DWORD
effect = DROPEFFECT_NONE;
137 effect |= DROPEFFECT_LINK;
139 effect |= DROPEFFECT_COPY;
141 effect |= DROPEFFECT_MOVE;
149 if (keyState & MK_SHIFT)
151 if (keyState & MK_CONTROL)
153 if (keyState & MK_ALT)
191 CursorEntry() : cacheKey(0) {}
193 pixmap(
p), cacheKey(cK), cursor(
c), hotSpot(
h) {}
201 typedef QMap<Qt::DropAction, CursorEntry> ActionCursorMap;
205 QPointer<QWindow> m_windowUnderMouse;
206 Qt::MouseButtons m_currentButtons;
207 ActionCursorMap m_cursors;
210#ifndef QT_NO_DEBUG_STREAM
219 , m_currentButtons(
Qt::NoButton)
222 qCDebug(lcQpaMime) << __FUNCTION__ << m_mode;
228 delete m_touchDragWindow;
229 qCDebug(lcQpaMime) << __FUNCTION__;
232#ifndef QT_NO_DEBUG_STREAM
235 d <<
"CursorEntry:" << e.pixmap.
size() <<
'#' << e.cacheKey
236 <<
"HCURSOR" << e.cursor->
handle() <<
"hotspot:" << e.hotSpot;
253 if (!platformScreen) {
255 platformScreen = primaryScreen->handle();
260 if (GetSystemMetrics (SM_REMOTESESSION) != 0) {
265 if (
pixmap.width() > rdpLargeCursor ||
pixmap.height() > rdpLargeCursor)
269 qreal pixmapScaleFactor = 1;
270 qreal hotSpotScaleFactor = 1;
273 pixmapScaleFactor = hotSpotScaleFactor /
pixmap.devicePixelRatio();
282 int actionCount = int(
sizeof(actions) /
sizeof(actions[0]));
288 for (
int cnum = 0; cnum < actionCount; ++cnum) {
291 if (cursorPixmap.
isNull() && platformCursor)
294 const auto it = m_cursors.
find(action);
297 if (cursorPixmap.
isNull()) {
298 qWarning(
"%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action);
303 QPixmap newPixmap = cursorPixmap;
306 const int x1 =
qMin(-hotSpot.
x(), 0);
308 const int y1 =
qMin(-hotSpot.
y(), 0);
314 p.drawPixmap(pmDest, scaledPixmap);
315 p.drawPixmap(
qMax(0, hotSpot.
x()),
qMax(0, hotSpot.
y()), cursorPixmap);
316 newPixmap = newCursor;
322 if (
it == m_cursors.
end())
328#ifndef QT_NO_DEBUG_OUTPUT
329 if (lcQpaMime().isDebugEnabled())
330 qCDebug(lcQpaMime) << __FUNCTION__ <<
"pixmap" <<
pixmap.size() << m_cursors.
size() <<
"cursors:\n" << m_cursors;
338QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
348 result = DRAGDROP_S_CANCEL;
351 if (buttons && !m_currentButtons) {
352 m_currentButtons = buttons;
353 }
else if (m_currentButtons != buttons) {
359 case DRAGDROP_S_DROP:
360 case DRAGDROP_S_CANCEL:
361 if (!m_windowUnderMouse.
isNull() && m_mode !=
TouchDrag && fEscapePressed == FALSE
381 qCDebug(lcQpaMime) << __FUNCTION__ <<
"fEscapePressed=" << fEscapePressed
382 <<
"grfKeyState=" << grfKeyState <<
"buttons" << m_currentButtons
385 return ResultFromScode(
result);
392QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
401 if (
it == m_cursors.
constEnd() || (currentCacheKey && currentCacheKey !=
it.value().cacheKey)) {
407 const CursorEntry &e =
it.value();
410 SetCursor(e.cursor->handle());
416 if (!m_touchDragWindow)
419 m_touchDragWindow->setFramePosition(
QCursor::pos() - e.hotSpot);
420 if (!m_touchDragWindow->isVisible())
421 m_touchDragWindow->
show();
424 return ResultFromScode(S_OK);
427 return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
444 qCDebug(lcQpaMime) << __FUNCTION__ <<
this <<
w;
449 qCDebug(lcQpaMime) << __FUNCTION__ <<
this;
452void QWindowsOleDropTarget::handleDrag(
QWindow *
window, DWORD grfKeyState,
453 const QPoint &point, LPDWORD pdwEffect)
466 QWindowSystemInterface::handleDrag(
window, windowsDrag->dropData(),
467 m_lastPoint, actions,
475 m_chosenEffect = DROPEFFECT_NONE;
477 *pdwEffect = m_chosenEffect;
478 qCDebug(lcQpaMime) << __FUNCTION__ << m_window
479 << windowsDrag->dropData() <<
" supported actions=" << actions
481 <<
" accepted: " << response.
isAccepted() << action
482 << m_answerRect <<
" effect" << *pdwEffect;
485QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
486QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
487 POINTL pt, LPDWORD pdwEffect)
490 dh->DragEnter(
reinterpret_cast<HWND
>(m_window->winId()),
pDataObj,
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
493 <<
"pt=" <<
pt.x <<
pt.y;
498 handleDrag(m_window,
grfKeyState, point, pdwEffect);
502QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
506 dh->DragOver(
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
509 <<
"pt=" <<
pt.x <<
pt.y;
512 if ((tmpPoint == m_lastPoint || m_answerRect.
contains(tmpPoint))
514 *pdwEffect = m_chosenEffect;
515 qCDebug(lcQpaMime) << __FUNCTION__ <<
"compressed event";
519 handleDrag(m_window,
grfKeyState, tmpPoint, pdwEffect);
523QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
529 qCDebug(lcQpaMime) << __FUNCTION__ <<
' ' << m_window;
545#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
547QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
548QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
549 POINTL pt, LPDWORD pdwEffect)
552 dh->Drop(
pDataObj,
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
554 qCDebug(lcQpaMime) << __FUNCTION__ <<
' ' << m_window
565 QWindowSystemInterface::handleDrop(m_window, windowsDrag->dropData(),
577 m_chosenEffect = DROPEFFECT_MOVE;
579 m_chosenEffect = DROPEFFECT_COPY;
580 HGLOBAL hData = GlobalAlloc(0,
sizeof(DWORD));
582 auto *moveEffect =
reinterpret_cast<DWORD *
>(GlobalLock(hData));
583 *moveEffect = DROPEFFECT_MOVE;
587 medium.tymed = TYMED_HGLOBAL;
588 medium.hGlobal = hData;
590 format.cfFormat = CLIPFORMAT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT));
591 format.tymed = TYMED_HGLOBAL;
595 windowsDrag->dropDataObject()->SetData(&
format, &medium,
true);
601 m_chosenEffect = DROPEFFECT_NONE;
603 *pdwEffect = m_chosenEffect;
605 windowsDrag->releaseDropDataObject();
616bool QWindowsDrag::m_canceled =
false;
622 if (m_cachedDropTargetHelper)
623 m_cachedDropTargetHelper->Release();
633 return drag->mimeData();
641 if (!m_cachedDropTargetHelper) {
642 CoCreateInstance(CLSID_DragDropHelper,
nullptr, CLSCTX_INPROC_SERVER,
643 IID_IDropTargetHelper,
644 reinterpret_cast<void**
>(&m_cachedDropTargetHelper));
646 return m_cachedDropTargetHelper;
654 const bool hasMouseCapture = underMouse &&
static_cast<QWindowsWindow *
>(underMouse->handle())->hasMouseCapture();
655 const HWND hwnd = hasMouseCapture ?
reinterpret_cast<HWND
>(underMouse->winId()) : ::GetFocus();
656 bool starting =
false;
660 if (::GetMessage(&msg, hwnd, 0, 0) > 0) {
662 if (msg.message == WM_MOUSEMOVE) {
665 if (!starting && (msg.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2)) == 0)
668 return ::DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
673 const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
675 POINTER_INFO pointerInfo{};
676 if (!GetPointerInfo(pointerId, &pointerInfo))
679 if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
681 DWORD
flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
682 if (IS_POINTER_FIRSTBUTTON_WPARAM(msg.wParam))
683 flags |= MOUSEEVENTF_LEFTDOWN;
684 if (IS_POINTER_SECONDBUTTON_WPARAM(msg.wParam))
685 flags |= MOUSEEVENTF_RIGHTDOWN;
686 if (IS_POINTER_THIRDBUTTON_WPARAM(msg.wParam))
687 flags |= MOUSEEVENTF_MIDDLEDOWN;
691 if (::GetCursorPos(&pt)) {
694 if ((
flags & MOUSEEVENTF_LEFTDOWN ||
flags & MOUSEEVENTF_RIGHTDOWN ||
flags & MOUSEEVENTF_MIDDLEDOWN)
695 && (pt.x != pointerInfo.ptPixelLocation.x || pt.y != pointerInfo.ptPixelLocation.y)) {
697 const int origin_x = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
698 const int origin_y = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
699 const int virt_w = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
700 const int virt_h = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
701 const int virt_x = pointerInfo.ptPixelLocation.x - origin_x;
702 const int virt_y = pointerInfo.ptPixelLocation.y - origin_y;
705 input.type = INPUT_MOUSE;
706 input.mi.dx =
static_cast<DWORD
>(virt_x * (65535.0 / virt_w));
707 input.mi.dy =
static_cast<DWORD
>(virt_y * (65535.0 / virt_h));
736 QWindowsDrag::m_canceled =
false;
738 windowDropSource->createCursors();
740 const Qt::DropActions possibleActions =
drag->supportedActions();
742 qCDebug(lcQpaMime) <<
'>' << __FUNCTION__ <<
"possible Actions=0x"
743 <<
Qt::hex << int(possibleActions) <<
"effects=0x" << allowedEffects <<
Qt::dec;
745 const DWORD reportedPerformedEffect =
dropDataObject->reportedPerformedEffect();
746 if (
r == DRAGDROP_S_DROP) {
747 if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
749 resultEffect = DROPEFFECT_MOVE;
755 if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) {
756 qWarning(
"%s: Forcing Qt::CopyAction", __FUNCTION__);
763 windowDropSource->Release();
764 qCDebug(lcQpaMime) <<
'<' << __FUNCTION__ <<
Qt::hex <<
"allowedEffects=0x" << allowedEffects
765 <<
"reportedPerformedEffect=0x" << reportedPerformedEffect
766 <<
" resultEffect=0x" << resultEffect <<
"hr=0x" << int(
r) <<
Qt::dec <<
"dropAction=" << dragResult;
777 qCDebug(lcQpaMime) << __FUNCTION__ << m_dropDataObject;
778 if (m_dropDataObject) {
779 m_dropDataObject->Release();
780 m_dropDataObject =
nullptr;
static void processEvents(QEventLoop::ProcessEventsFlags flags=QEventLoop::AllEvents)
Processes some pending events for the calling thread according to the specified flags.
static QPoint pos()
Returns the position of the cursor (hot spot) of the primary screen in global screen coordinates.
static QDragManager * self()
QPixmap pixmap() const
Returns the pixmap used to represent the data in a drag and drop operation.
QPixmap dragCursor(Qt::DropAction action) const
Returns the drag cursor for the action.
QPoint hotSpot() const
Returns the position of the hot spot relative to the top-left corner of the cursor.
QScreen * primaryScreen
the primary (or default) screen of the application.
static qreal factor(C *context)
iterator insert(const Key &key, const T &value)
const_iterator constFind(const Key &key) const
iterator find(const Key &key)
const_iterator constEnd() const
QObject * parent() const
Returns a pointer to the parent object.
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
void update()
Marks the entire window as dirty and schedules a repaint.
qreal devicePixelRatio() const
The QPaintEvent class contains event parameters for paint events.
The QPainter class performs low-level painting on widgets and other paint devices.
void drawPixmap(const QRectF &targetRect, const QPixmap &pixmap, const QRectF &sourceRect)
Draws the rectangular portion source of the given pixmap into the given target in the paint device.
Returns a copy of the pixmap that is transformed using the given transformation transform and transfo...
int height() const
Returns the height of the pixmap.
QPixmap scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
QSize size() const
Returns the size of the pixmap.
bool isNull() const
Returns true if this is a null pixmap; otherwise returns false.
int width() const
Returns the width of the pixmap.
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the pixmap.
qreal devicePixelRatio() const
Returns the device pixel ratio for the pixmap.
qint64 cacheKey() const
Returns a number that identifies this QPixmap.
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr int x() const noexcept
Returns the x coordinate of this point.
constexpr int y() const noexcept
Returns the y coordinate of this point.
T * data() const noexcept
bool isNull() const noexcept
bool contains(const QRect &r, bool proper=false) const noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
The QScreen class is used to query screen properties. \inmodule QtGui.
static bool handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods=Qt::NoModifier, Qt::MouseEventSource source=Qt::MouseEventNotSynthesized)
void show()
Shows the window.
QSurfaceFormat format() const override
Returns the actual format of this window.
Singleton container for all relevant information.
static QWindowsContext * instance()
Platform cursor implementation.
static QPoint mousePosition()
static HCURSOR createPixmapCursor(QPixmap pixmap, const QPoint &hotSpot, qreal scaleFactor=1)
static State cursorState()
QPixmap dragDefaultCursor(Qt::DropAction action) const
A toplevel window showing the drag icon in case of touch drag.
void setPixmap(const QPixmap &p)
void paintEvent(QPaintEvent *) override
Handles paint events passed in the event parameter.
QWindowsDragCursorWindow(QWindow *parent=nullptr)
Windows drag implementation.
IDataObject * dropDataObject() const
QMimeData * dropData()
Return data for a drop in process.
static QWindowsDrag * instance()
void releaseDropDataObject()
IDropTargetHelper * dropHelper()
May be used to handle extended cursors functionality for drags from outside the app.
Qt::DropAction drag(QDrag *drag) override
QWindowsOleDataObject subclass specialized for handling Drag&Drop.
IDataObject * retrieveDataObject() const override
static QWindowsIntegration * instance()
static Qt::MouseButtons queryMouseButtons()
Implementation of IDropSource.
~QWindowsOleDropSource() override
STDMETHOD QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) override
Check for cancel.
void createCursors()
Blend custom pixmap with cursors.
QWindowsOleDropSource(QWindowsDrag *drag)
STDMETHOD GiveFeedback(DWORD dwEffect) override
Give feedback: Change cursor according to action.
friend QDebug operator<<(QDebug, const QWindowsOleDropSource::CursorEntry &)
~QWindowsOleDropTarget() override
LPDATAOBJECT DWORD grfKeyState
LPDATAOBJECT DWORD POINTL pt
STDMETHOD DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) override
QWindowsOleDropTarget(QWindow *w)
STDMETHOD DragLeave() override
EGLImageKHR int int EGLuint64KHR * modifiers
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
@ WindowDoesNotAcceptFocus
@ WindowTransparentForInput
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
int qRound(qfloat16 d) noexcept
static QByteArray cacheKey(Args &&...args)
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qMax(const T &a, const T &b)
GLfloat GLfloat GLfloat w
[0]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
GLsizei GLsizei GLchar * source
GLfixed GLfixed GLfixed y2
GLenum GLenum GLenum input
#define QStringLiteral(str)
LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND, UINT, WPARAM, LPARAM)
QSharedPointer< CursorHandle > CursorHandlePtr
static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect)
static Qt::DropActions translateToQDragDropActions(DWORD pdwEffects)
static Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
static Qt::KeyboardModifiers lastModifiers
QDebug operator<<(QDebug d, const QWindowsOleDropSource::CursorEntry &e)
static Qt::DropAction translateToQDragDropAction(DWORD pdwEffect)
static Qt::MouseButtons lastButtons
static DWORD translateToWinDragEffects(Qt::DropActions action)
QGraphicsOpacityEffect * effect
the effect attached to this item
static QPoint mapFromGlobal(const HWND hwnd, const QPoint &)