From 0b8d0804219b7e2e6179112d663b989d5b749d17 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 17 Aug 2011 15:58:39 +0200 Subject: Add Windows to the Lighthouse. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add an initial Lighthouse plugin for the Windows operating system. Change-Id: I6934562266e1aa0ac270bf6107df05a9e56ef82c Reviewed-on: http://codereview.qt.nokia.com/3107 Reviewed-by: Oliver Wolff Reviewed-by: Samuel Rødal --- src/plugins/platforms/windows/qwindowsdrag.cpp | 721 +++++++++++++++++++++++++ 1 file changed, 721 insertions(+) create mode 100644 src/plugins/platforms/windows/qwindowsdrag.cpp (limited to 'src/plugins/platforms/windows/qwindowsdrag.cpp') diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp new file mode 100644 index 0000000000..1535437a32 --- /dev/null +++ b/src/plugins/platforms/windows/qwindowsdrag.cpp @@ -0,0 +1,721 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (info@qt.nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsdrag.h" +#include "qwindowscontext.h" +#include "qwindowsclipboard.h" +#include "qwindowsintegration.h" +#include "qwindowsole.h" +#include "qtwindows_additional.h" +#include "qwindowswindow.h" +#include "qwindowsmousehandler.h" +#include "qwindowscursor.h" + +#include +#include +#include +#include + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QWindowsDropMimeData + \brief Special mime data class for data retrieval from Drag operations. + + Implementation of QWindowsInternalMimeDataBase which retrieves the + current drop data object from QWindowsDrag. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +IDataObject *QWindowsDropMimeData::retrieveDataObject() const +{ + return QWindowsDrag::instance()->dropDataObject(); +} + +static inline Qt::DropActions translateToQDragDropActions(DWORD pdwEffects) +{ + Qt::DropActions actions = Qt::IgnoreAction; + if (pdwEffects & DROPEFFECT_LINK) + actions |= Qt::LinkAction; + if (pdwEffects & DROPEFFECT_COPY) + actions |= Qt::CopyAction; + if (pdwEffects & DROPEFFECT_MOVE) + actions |= Qt::MoveAction; + return actions; +} + +static inline Qt::DropAction translateToQDragDropAction(DWORD pdwEffect) +{ + if (pdwEffect & DROPEFFECT_LINK) + return Qt::LinkAction; + if (pdwEffect & DROPEFFECT_COPY) + return Qt::CopyAction; + if (pdwEffect & DROPEFFECT_MOVE) + return Qt::MoveAction; + return Qt::IgnoreAction; +} + +static inline DWORD translateToWinDragEffects(Qt::DropActions action) +{ + DWORD effect = DROPEFFECT_NONE; + if (action & Qt::LinkAction) + effect |= DROPEFFECT_LINK; + if (action & Qt::CopyAction) + effect |= DROPEFFECT_COPY; + if (action & Qt::MoveAction) + effect |= DROPEFFECT_MOVE; + return effect; +} + +static inline Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState) +{ + Qt::KeyboardModifiers modifiers = Qt::NoModifier; + + if (keyState & MK_SHIFT) + modifiers |= Qt::ShiftModifier; + if (keyState & MK_CONTROL) + modifiers |= Qt::ControlModifier; + if (keyState & MK_ALT) + modifiers |= Qt::AltModifier; + + return modifiers; +} + +/*! + \class QWindowsOleDropSource + \brief Implementation of IDropSource + + Used for drag operations. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +class QWindowsOleDropSource : public IDropSource +{ +public: + QWindowsOleDropSource(); + virtual ~QWindowsOleDropSource(); + + void createCursors(); + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj); + STDMETHOD_(ULONG,AddRef)(void); + STDMETHOD_(ULONG,Release)(void); + + // IDropSource methods + STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState); + STDMETHOD(GiveFeedback)(DWORD dwEffect); + +private: + typedef QMap ActionCursorMap; + + inline void clearCursors(); + + Qt::MouseButtons m_currentButtons; + Qt::DropAction m_currentAction; + ActionCursorMap m_cursors; + + ULONG m_refs; +}; + +QWindowsOleDropSource::QWindowsOleDropSource() : + m_currentButtons(Qt::NoButton), m_currentAction(Qt::IgnoreAction), + m_refs(1) +{ + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); +} + +QWindowsOleDropSource::~QWindowsOleDropSource() +{ + clearCursors(); + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); +} + +void QWindowsOleDropSource::createCursors() +{ + QDragManager *manager = QDragManager::self(); + if (!manager || !manager->object) + return; + const QPixmap pixmap = manager->object->pixmap(); + const bool hasPixmap = !pixmap.isNull(); + if (!hasPixmap && manager->dragPrivate()->customCursors.isEmpty()) + return; + + QList actions; + actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction; + if (hasPixmap) + actions << Qt::IgnoreAction; + const QPoint hotSpot = manager->object->hotSpot(); + for (int cnum = 0; cnum < actions.size(); ++cnum) { + const QPixmap cpm = manager->dragCursor(actions.at(cnum)); + 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 QRect srcRect = pixmap.rect(); + const QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y())); + const QPoint newHotSpot = hotSpot; + QPixmap newCursor(w, h); + if (hasPixmap) { + newCursor.fill(QColor(0, 0, 0, 0)); + QPainter p(&newCursor); + 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::clearCursors() +{ + if (!m_cursors.isEmpty()) { + const ActionCursorMap::const_iterator cend = m_cursors.constEnd(); + for (ActionCursorMap::const_iterator it = m_cursors.constBegin(); it != cend; ++it) + DestroyCursor(it.value()); + m_cursors.clear(); + } +} + +//--------------------------------------------------------------------- +// IUnknown Methods +//--------------------------------------------------------------------- + +STDMETHODIMP +QWindowsOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv) +{ + if (iid == IID_IUnknown || iid == IID_IDropSource) { + *ppv = this; + ++m_refs; + return NOERROR; + } + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropSource::AddRef(void) +{ + return ++m_refs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropSource::Release(void) +{ + if (--m_refs == 0) { + delete this; + return 0; + } + return m_refs; +} + +/*! + \brief Check for cancel. +*/ + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState) +{ + HRESULT hr = S_OK; + do { + if (fEscapePressed || QWindowsDrag::instance()->dragBeingCancelled()) { + hr = ResultFromScode(DRAGDROP_S_CANCEL); + break; + } + + // grfKeyState is broken on CE & some Windows XP versions, + // therefore we need to check the state manually + if ((GetAsyncKeyState(VK_LBUTTON) == 0) + && (GetAsyncKeyState(VK_MBUTTON) == 0) + && (GetAsyncKeyState(VK_RBUTTON) == 0)) { + hr = ResultFromScode(DRAGDROP_S_DROP); + break; + } + + const Qt::MouseButtons buttons = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + if (m_currentButtons == Qt::NoButton) { + m_currentButtons = buttons; + } else { + // Button changed: Complete Drop operation. + if (!(m_currentButtons & buttons)) { + hr = ResultFromScode(DRAGDROP_S_DROP); + break; + } + } + + QGuiApplication::processEvents(); + + } while (false); + + QDragManager::self()->willDrop = hr == DRAGDROP_S_DROP; + + if (QWindowsContext::verboseOLE + && (QWindowsContext::verboseOLE > 1 || hr != S_OK)) + qDebug("%s fEscapePressed=%d, grfKeyState=%lu buttons=%d willDrop = %d returns 0x%x", + __FUNCTION__, fEscapePressed,grfKeyState, int(m_currentButtons), + QDragManager::self()->willDrop, int(hr)); + return hr; +} + +/*! + \brief Give feedback: Change cursor accoding to action. +*/ + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropSource::GiveFeedback(DWORD dwEffect) +{ + const Qt::DropAction action = translateToQDragDropAction(dwEffect); + + if (QWindowsContext::verboseOLE > 2) + qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action); + + if (m_currentAction != action) { + m_currentAction = action; + QDragManager::self()->emitActionChanged(m_currentAction); + } + + const ActionCursorMap::const_iterator it = m_cursors.constFind(m_currentAction); + if (it != m_cursors.constEnd()) { + SetCursor(it.value()); + return ResultFromScode(S_OK); + } + + return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS); +} + +/*! + \class QWindowsOleDropTarget + \brief Implementation of IDropTarget + + To be registered for each window. Currently, drop sites + are enabled for top levels. The child window handling + (sending DragEnter/Leave, etc) is handled in here. + + \sa QWindowsDrag + \ingroup qt-lighthouse-win +*/ + +QWindowsOleDropTarget::QWindowsOleDropTarget(QWindow *w) : + m_refs(1), m_window(w), m_currentWindow(0), m_chosenEffect(0), m_lastKeyState(0) +{ + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << this << w; +} + +QWindowsOleDropTarget::~QWindowsOleDropTarget() +{ + if (QWindowsContext::verboseOLE) + qDebug("%s %p", __FUNCTION__, this); +} + +STDMETHODIMP +QWindowsOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv) +{ + if (iid == IID_IUnknown || iid == IID_IDropTarget) { + *ppv = this; + AddRef(); + return NOERROR; + } + *ppv = NULL; + return ResultFromScode(E_NOINTERFACE); +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropTarget::AddRef(void) +{ + return ++m_refs; +} + +STDMETHODIMP_(ULONG) +QWindowsOleDropTarget::Release(void) +{ + if (--m_refs == 0) { + delete this; + return 0; + } + return m_refs; +} + +QWindow *QWindowsOleDropTarget::findDragOverWindow(const POINTL &pt) const +{ + if (QWindowsWindow *child = + QWindowsWindow::baseWindowOf(m_window)->childAtScreenPoint(QPoint(pt.x, pt.y))) + return child->window(); + return m_window; +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + if (QWindowsContext::verboseOLE) + qDebug("%s widget=%p key=%lu, pt=%ld,%ld", __FUNCTION__, m_window, grfKeyState, pt.x, pt.y); + + QWindowsDrag::instance()->setDropDataObject(pDataObj); + pDataObj->AddRef(); + m_currentWindow = m_window; + sendDragEnterEvent(m_window, grfKeyState, pt, pdwEffect); + *pdwEffect = m_chosenEffect; + return NOERROR; +} + +void QWindowsOleDropTarget::sendDragEnterEvent(QWindow *dragEnterWidget, + DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + Q_ASSERT(dragEnterWidget); + + m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dragEnterWidget, QPoint(pt.x,pt.y)); + m_lastKeyState = grfKeyState; + + m_chosenEffect = DROPEFFECT_NONE; + + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + const Qt::MouseButtons mouseButtons + = QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState); + const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); + const Qt::KeyboardModifiers keyMods = toQtKeyboardModifiers(grfKeyState); + QDragEnterEvent enterEvent(m_lastPoint, actions, md, mouseButtons, keyMods); + QGuiApplication::sendEvent(m_currentWindow, &enterEvent); + m_answerRect = enterEvent.answerRect(); + if (QWindowsContext::verboseOLE) + qDebug() << __FUNCTION__ << " sent drag enter to " << m_window + << *md << " actions=" << actions + << " mods=" << keyMods << " accepted: " + << enterEvent.isAccepted(); + + if (enterEvent.isAccepted()) + m_chosenEffect = translateToWinDragEffects(enterEvent.dropAction()); + // Documentation states that a drag move event is sent immediately after + // a drag enter event. This will honor widgets overriding dragMoveEvent only: + if (enterEvent.isAccepted()) { + QDragMoveEvent moveEvent(m_lastPoint, actions, md, mouseButtons, keyMods); + m_answerRect = enterEvent.answerRect(); + moveEvent.setDropAction(enterEvent.dropAction()); + moveEvent.accept(); // accept by default, since enter event was accepted. + + QGuiApplication::sendEvent(dragEnterWidget, &moveEvent); + if (moveEvent.isAccepted()) { + m_answerRect = moveEvent.answerRect(); + m_chosenEffect = translateToWinDragEffects(moveEvent.dropAction()); + } else { + m_chosenEffect = DROPEFFECT_NONE; + } + } +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect) +{ + QWindow *dragOverWindow = findDragOverWindow(pt); + + const QPoint tmpPoint = QWindowsGeometryHint::mapFromGlobal(dragOverWindow, QPoint(pt.x,pt.y)); + // see if we should compress this event + if ((tmpPoint == m_lastPoint || m_answerRect.contains(tmpPoint)) + && m_lastKeyState == grfKeyState) { + *pdwEffect = m_chosenEffect; + return NOERROR; + } + + if (QWindowsContext::verboseOLE > 1) + qDebug().nospace() << '>' << __FUNCTION__ << ' ' << m_window << " current " + << dragOverWindow << " key=" << grfKeyState + << " pt=" < dragOverWindowGuard(dragOverWindow); + // Send drag leave event to the previous drag widget. + // Drag-Over widget might be deleted in DragLeave, + // (tasktracker 218353). + QDragLeaveEvent dragLeave; + if (m_currentWindow) + QGuiApplication::sendEvent(m_currentWindow, &dragLeave); + if (!dragOverWindowGuard) { + dragOverWindow = findDragOverWindow(pt); + } + // Send drag enter event to the current drag widget. + m_currentWindow = dragOverWindow; + sendDragEnterEvent(dragOverWindow, grfKeyState, pt, pdwEffect); + } + + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + + const Qt::DropActions actions = translateToQDragDropActions(*pdwEffect); + + QDragMoveEvent oldEvent(m_lastPoint, actions, md, + QWindowsMouseHandler::keyStateToMouseButtons(m_lastKeyState), + toQtKeyboardModifiers(m_lastKeyState)); + + m_lastPoint = tmpPoint; + m_lastKeyState = grfKeyState; + + QDragMoveEvent e(tmpPoint, actions, md, + QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), + toQtKeyboardModifiers(grfKeyState)); + if (m_chosenEffect != DROPEFFECT_NONE) { + if (oldEvent.dropAction() == e.dropAction() && + oldEvent.keyboardModifiers() == e.keyboardModifiers()) + e.setDropAction(translateToQDragDropAction(m_chosenEffect)); + e.accept(); + } + QGuiApplication::sendEvent(dragOverWindow, &e); + + m_answerRect = e.answerRect(); + if (e.isAccepted()) + m_chosenEffect = translateToWinDragEffects(e.dropAction()); + else + m_chosenEffect = DROPEFFECT_NONE; + *pdwEffect = m_chosenEffect; + + if (QWindowsContext::verboseOLE > 1) + qDebug("<%s effect=0x%lx", __FUNCTION__, m_chosenEffect); + return NOERROR; +} + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::DragLeave() +{ + if (QWindowsContext::verboseOLE) + qDebug().nospace() <<__FUNCTION__ << ' ' << m_window; + + m_currentWindow = 0; + QDragLeaveEvent e; + QGuiApplication::sendEvent(m_window, &e); + QWindowsDrag::instance()->releaseDropDataObject(); + + return NOERROR; +} + +#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON) + +QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP +QWindowsOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, + POINTL pt, LPDWORD pdwEffect) +{ + QWindow *dropWindow = findDragOverWindow(pt); + + if (QWindowsContext::verboseOLE) + qDebug().nospace() << __FUNCTION__ << ' ' << m_window + << " on " << dropWindow + << " keys=" << grfKeyState << " pt=" + << pt.x << ',' << pt.y; + + m_lastPoint = QWindowsGeometryHint::mapFromGlobal(dropWindow, QPoint(pt.x,pt.y)); + // grfKeyState does not all ways contain button state in the drop so if + // it doesn't then use the last known button state; + if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0) + grfKeyState |= m_lastKeyState & KEY_STATE_BUTTON_MASK; + m_lastKeyState = grfKeyState; + + QWindowsDrag *windowsDrag = QWindowsDrag::instance(); + QDragManager *manager = QDragManager::self(); + QMimeData *md = manager->dropData(); + QDropEvent e(m_lastPoint, translateToQDragDropActions(*pdwEffect), md, + QWindowsMouseHandler::keyStateToMouseButtons(grfKeyState), + toQtKeyboardModifiers(grfKeyState)); + if (m_chosenEffect != DROPEFFECT_NONE) + e.setDropAction(translateToQDragDropAction(m_chosenEffect)); + + QGuiApplication::sendEvent(dropWindow, &e); + if (m_chosenEffect != DROPEFFECT_NONE) + e.accept(); + + if (e.isAccepted()) { + if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) { + if (e.dropAction() == Qt::MoveAction) + m_chosenEffect = DROPEFFECT_MOVE; + else + m_chosenEffect = DROPEFFECT_COPY; + HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD)); + if (hData) { + DWORD *moveEffect = (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 = 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(e.dropAction()); + } + } else { + m_chosenEffect = DROPEFFECT_NONE; + } + *pdwEffect = m_chosenEffect; + + windowsDrag->releaseDropDataObject(); + return NOERROR; +} + +/*! + \class QWindowsDrag + \brief Windows drag implementation. + + \ingroup qt-lighthouse-win +*/ + +QWindowsDrag::QWindowsDrag() : m_dropDataObject(0), m_dragBeingCancelled(false) +{ +} + +QWindowsDrag::~QWindowsDrag() +{ +} + +void QWindowsDrag::startDrag() +{ + // TODO: Accessibility handling? + QDragManager *dragManager = QDragManager::self(); + QMimeData *dropData = dragManager->dropData(); + m_dragBeingCancelled = false; + + DWORD resultEffect; + QWindowsOleDropSource *windowDropSource = new QWindowsOleDropSource(); + windowDropSource->createCursors(); + QWindowsOleDataObject *dropDataObject = new QWindowsOleDataObject(dropData); + const Qt::DropActions possibleActions = dragManager->possible_actions; + const DWORD allowedEffects = translateToWinDragEffects(possibleActions); + if (QWindowsContext::verboseOLE) + qDebug(">%s possible Actions=%x, effects=0x%lx", __FUNCTION__, + int(possibleActions), allowedEffects); + const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect); + const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect(); + Qt::DropAction ret = Qt::IgnoreAction; + if (r == DRAGDROP_S_DROP) { + if (reportedPerformedEffect == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) { + ret = Qt::TargetMoveAction; + resultEffect = DROPEFFECT_MOVE; + } else { + ret = translateToQDragDropAction(resultEffect); + } + // Force it to be a copy if an unsupported operation occurred. + // This indicates a bug in the drop target. + if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects)) + ret = Qt::CopyAction; + } else { + dragManager->setCurrentTarget(0); + } + + // clean up + dropDataObject->releaseQt(); + dropDataObject->Release(); // Will delete obj if refcount becomes 0 + windowDropSource->Release(); // Will delete src if refcount becomes 0 + if (QWindowsContext::verboseOLE) + qDebug("<%s allowedEffects=0x%lx, reportedPerformedEffect=0x%lx, resultEffect=0x%lx, hr=0x%x, dropAction=%d", + __FUNCTION__, allowedEffects, reportedPerformedEffect, resultEffect, int(r), ret); +} + +void QWindowsDrag::move(const QMouseEvent *me) +{ + const QPoint pos = me->pos(); + if (QWindowsContext::verboseOLE) + qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); +} + +void QWindowsDrag::drop(const QMouseEvent *me) +{ + const QPoint pos = me->pos(); + if (QWindowsContext::verboseOLE) + qDebug("%s %d %d", __FUNCTION__, pos.x(), pos.y()); +} + +void QWindowsDrag::cancel() +{ + // TODO: Accessibility handling? + if (QWindowsContext::verboseOLE) + qDebug("%s", __FUNCTION__); + m_dragBeingCancelled = true; +} + +QWindowsDrag *QWindowsDrag::instance() +{ + return static_cast(QWindowsIntegration::instance()->drag()); +} + +void QWindowsDrag::releaseDropDataObject() +{ + if (QWindowsContext::verboseOLE) + qDebug("%s %p", __FUNCTION__, m_dropDataObject); + if (m_dropDataObject) { + m_dropDataObject->Release(); + m_dropDataObject = 0; + } +} + +QT_END_NAMESPACE -- cgit v1.2.3