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>
80 qCDebug(lcQpaMime) << __FUNCTION__ <<
p.cacheKey() << newSize;
82 if (oldSize != newSize) {
83 const qreal pixDevicePixelRatio =
p.devicePixelRatio();
85 newSize /=
qRound(pixDevicePixelRatio);
111 if (pdwEffects & DROPEFFECT_LINK)
113 if (pdwEffects & DROPEFFECT_COPY)
115 if (pdwEffects & DROPEFFECT_MOVE)
122 if (pdwEffect & DROPEFFECT_LINK)
124 if (pdwEffect & DROPEFFECT_COPY)
126 if (pdwEffect & DROPEFFECT_MOVE)
133 DWORD
effect = DROPEFFECT_NONE;
135 effect |= DROPEFFECT_LINK;
137 effect |= DROPEFFECT_COPY;
139 effect |= DROPEFFECT_MOVE;
147 if (keyState & MK_SHIFT)
149 if (keyState & MK_CONTROL)
151 if (keyState & MK_ALT)
189 CursorEntry() : cacheKey(0) {}
204 Qt::MouseButtons m_currentButtons;
205 ActionCursorMap m_cursors;
208#ifndef QT_NO_DEBUG_STREAM
217 , m_currentButtons(
Qt::NoButton)
220 qCDebug(lcQpaMime) << __FUNCTION__ << m_mode;
226 delete m_touchDragWindow;
227 qCDebug(lcQpaMime) << __FUNCTION__;
230#ifndef QT_NO_DEBUG_STREAM
233 d <<
"CursorEntry:" <<
e.pixmap.size() <<
'#' <<
e.cacheKey
234 <<
"HCURSOR" <<
e.cursor->handle() <<
"hotspot:" <<
e.hotSpot;
247 const bool hasPixmap = !
pixmap.isNull();
251 if (!platformScreen) {
253 platformScreen = primaryScreen->handle();
258 if (GetSystemMetrics (SM_REMOTESESSION) != 0) {
263 if (
pixmap.width() > rdpLargeCursor ||
pixmap.height() > rdpLargeCursor)
267 qreal pixmapScaleFactor = 1;
268 qreal hotSpotScaleFactor = 1;
271 pixmapScaleFactor = hotSpotScaleFactor /
pixmap.devicePixelRatio();
280 int actionCount = int(
sizeof(actions) /
sizeof(actions[0]));
286 for (
int cnum = 0; cnum < actionCount; ++cnum) {
289 if (cursorPixmap.
isNull() && platformCursor)
292 const auto it = m_cursors.
find(action);
293 if (
it != m_cursors.
end() &&
it.value().cacheKey == cacheKey)
295 if (cursorPixmap.
isNull()) {
296 qWarning(
"%s: Unable to obtain drag cursor for %d.", __FUNCTION__, action);
301 QPixmap newPixmap = cursorPixmap;
304 const int x1 =
qMin(-hotSpot.
x(), 0);
306 const int y1 =
qMin(-hotSpot.
y(), 0);
312 p.drawPixmap(pmDest, scaledPixmap);
313 p.drawPixmap(
qMax(0, hotSpot.
x()),
qMax(0, hotSpot.
y()), cursorPixmap);
314 newPixmap = newCursor;
320 if (
it == m_cursors.
end())
326#ifndef QT_NO_DEBUG_OUTPUT
327 if (lcQpaMime().isDebugEnabled())
328 qCDebug(lcQpaMime) << __FUNCTION__ <<
"pixmap" <<
pixmap.size() << m_cursors.
size() <<
"cursors:\n" << m_cursors;
336QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
346 result = DRAGDROP_S_CANCEL;
349 if (buttons && !m_currentButtons) {
350 m_currentButtons = buttons;
351 }
else if (m_currentButtons != buttons) {
357 case DRAGDROP_S_DROP:
358 case DRAGDROP_S_CANCEL:
359 if (!m_windowUnderMouse.
isNull() && m_mode !=
TouchDrag && fEscapePressed == FALSE
379 qCDebug(lcQpaMime) << __FUNCTION__ <<
"fEscapePressed=" << fEscapePressed
380 <<
"grfKeyState=" << grfKeyState <<
"buttons" << m_currentButtons
383 return ResultFromScode(
result);
390QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
399 if (
it == m_cursors.
constEnd() || (currentCacheKey && currentCacheKey !=
it.value().cacheKey)) {
405 const CursorEntry &
e =
it.value();
408 SetCursor(
e.cursor->handle());
414 if (!m_touchDragWindow)
417 m_touchDragWindow->setFramePosition(
QCursor::pos() -
e.hotSpot);
418 if (!m_touchDragWindow->isVisible())
419 m_touchDragWindow->
show();
422 return ResultFromScode(S_OK);
425 return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
442 qCDebug(lcQpaMime) << __FUNCTION__ <<
this <<
w;
447 qCDebug(lcQpaMime) << __FUNCTION__ <<
this;
450void QWindowsOleDropTarget::handleDrag(
QWindow *
window, DWORD grfKeyState,
451 const QPoint &point, LPDWORD pdwEffect)
464 QWindowSystemInterface::handleDrag(
window, windowsDrag->
dropData(),
465 m_lastPoint, actions,
473 m_chosenEffect = DROPEFFECT_NONE;
475 *pdwEffect = m_chosenEffect;
476 qCDebug(lcQpaMime) << __FUNCTION__ << m_window
477 << windowsDrag->
dropData() <<
" supported actions=" << actions
479 <<
" accepted: " << response.
isAccepted() << action
480 << m_answerRect <<
" effect" << *pdwEffect;
483QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
484QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState,
485 POINTL pt, LPDWORD pdwEffect)
488 dh->DragEnter(
reinterpret_cast<HWND
>(m_window->winId()),
pDataObj,
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
491 <<
"pt=" <<
pt.x <<
pt.y;
496 handleDrag(m_window,
grfKeyState, point, pdwEffect);
500QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
504 dh->DragOver(
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
507 <<
"pt=" <<
pt.x <<
pt.y;
510 if ((tmpPoint == m_lastPoint || m_answerRect.
contains(tmpPoint))
512 *pdwEffect = m_chosenEffect;
513 qCDebug(lcQpaMime) << __FUNCTION__ <<
"compressed event";
517 handleDrag(m_window,
grfKeyState, tmpPoint, pdwEffect);
521QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
527 qCDebug(lcQpaMime) << __FUNCTION__ <<
' ' << m_window;
542#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
544QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
545QWindowsOleDropTarget::Drop(LPDATAOBJECT pDataObj, DWORD grfKeyState,
546 POINTL pt, LPDWORD pdwEffect)
549 dh->Drop(
pDataObj,
reinterpret_cast<POINT*
>(&
pt), *pdwEffect);
551 qCDebug(lcQpaMime) << __FUNCTION__ <<
' ' << m_window
562 QWindowSystemInterface::handleDrop(m_window, windowsDrag->
dropData(),
574 m_chosenEffect = DROPEFFECT_MOVE;
576 m_chosenEffect = DROPEFFECT_COPY;
577 HGLOBAL hData = GlobalAlloc(0,
sizeof(DWORD));
579 auto *moveEffect =
reinterpret_cast<DWORD *
>(GlobalLock(hData));
580 *moveEffect = DROPEFFECT_MOVE;
584 medium.tymed = TYMED_HGLOBAL;
585 medium.hGlobal = hData;
587 format.cfFormat = CLIPFORMAT(RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT));
588 format.tymed = TYMED_HGLOBAL;
598 m_chosenEffect = DROPEFFECT_NONE;
600 *pdwEffect = m_chosenEffect;
613bool QWindowsDrag::m_canceled =
false;
614bool QWindowsDrag::m_dragging =
false;
620 if (m_cachedDropTargetHelper)
621 m_cachedDropTargetHelper->Release();
631 return drag->mimeData();
639 if (!m_cachedDropTargetHelper) {
640 CoCreateInstance(CLSID_DragDropHelper,
nullptr, CLSCTX_INPROC_SERVER,
641 IID_IDropTargetHelper,
642 reinterpret_cast<void**
>(&m_cachedDropTargetHelper));
644 return m_cachedDropTargetHelper;
652 const HWND hwnd = underMouse ?
reinterpret_cast<HWND
>(underMouse->winId()) :
::GetFocus();
653 bool starting =
false;
657 if (::GetMessage(&msg, hwnd, 0, 0) > 0) {
659 if (msg.message == WM_MOUSEMOVE) {
662 if (!starting && (msg.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2)) == 0)
665 return ::DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
670 const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
672 POINTER_INFO pointerInfo{};
673 if (!GetPointerInfo(pointerId, &pointerInfo))
676 if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
678 DWORD
flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
679 if (IS_POINTER_FIRSTBUTTON_WPARAM(msg.wParam))
680 flags |= MOUSEEVENTF_LEFTDOWN;
681 if (IS_POINTER_SECONDBUTTON_WPARAM(msg.wParam))
682 flags |= MOUSEEVENTF_RIGHTDOWN;
683 if (IS_POINTER_THIRDBUTTON_WPARAM(msg.wParam))
684 flags |= MOUSEEVENTF_MIDDLEDOWN;
688 if (::GetCursorPos(&pt)) {
691 if ((
flags & MOUSEEVENTF_LEFTDOWN ||
flags & MOUSEEVENTF_RIGHTDOWN ||
flags & MOUSEEVENTF_MIDDLEDOWN)
692 && (pt.x != pointerInfo.ptPixelLocation.x || pt.y != pointerInfo.ptPixelLocation.y)) {
694 const int origin_x = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
695 const int origin_y = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
696 const int virt_w = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
697 const int virt_h = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
698 const int virt_x = pointerInfo.ptPixelLocation.x - origin_x;
699 const int virt_y = pointerInfo.ptPixelLocation.y - origin_y;
702 input.type = INPUT_MOUSE;
703 input.mi.dx =
static_cast<DWORD
>(virt_x * (65535.0 / virt_w));
704 input.mi.dy =
static_cast<DWORD
>(virt_y * (65535.0 / virt_h));
733 QWindowsDrag::m_canceled =
false;
735 windowDropSource->createCursors();
737 const Qt::DropActions possibleActions =
drag->supportedActions();
739 qCDebug(lcQpaMime) <<
'>' << __FUNCTION__ <<
"possible Actions=0x"
740 <<
Qt::hex << int(possibleActions) <<
"effects=0x" << allowedEffects <<
Qt::dec;
742 QWindowsDrag::m_dragging =
true;
744 QWindowsDrag::m_dragging =
false;
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
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.
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.
void fill(const QColor &fillColor=Qt::white)
Fills the pixmap with the given color.
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.
bool isNull() const
Returns true if the referenced object has been destroyed or if there is no referenced object; otherwi...
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.
QWindowsScreenManager & screenManager()
QWindow * windowUnderMouse() const
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.
void setDropDataObject(IDataObject *dataObject)
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::KeyboardModifiers queryKeyboardModifiers()
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
const QWindowsScreen * screenAtDp(const QPoint &p) const
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
#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 &)
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent
virtual HRESULT STDMETHODCALLTYPE GetFocus(__RPC__deref_out_opt IRawElementProviderFragment **pRetVal)=0