src/gui/kernel/qdnd_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gui/kernel/qdnd_win.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1031 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qapplication.h"
+
+#include "qapplication_p.h"
+#include "qevent.h"
+#include "qpainter.h"
+#include "qwidget.h"
+#include "qbuffer.h"
+#include "qdatastream.h"
+#include "qcursor.h"
+#include "qt_windows.h"
+#include <shlobj.h>
+#ifndef QT_NO_ACCESSIBILITY
+#include "qaccessible.h"
+#endif
+#include "qdnd_p.h"
+#include "qdebug.h"
+
+#if defined(Q_OS_WINCE)
+#include "qguifunctions_wince.h"
+#endif
+
+// support for xbuttons
+#ifndef MK_XBUTTON1
+#define MK_XBUTTON1         0x0020
+#define MK_XBUTTON2         0x0040
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
+
+//---------------------------------------------------------------------
+//                    QOleDataObject Constructor
+//---------------------------------------------------------------------
+
+QOleDataObject::QOleDataObject(QMimeData *mimeData)
+{
+    m_refs = 1;
+    data = mimeData;
+    CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
+    performedEffect = DROPEFFECT_NONE;
+}
+
+QOleDataObject::~QOleDataObject()
+{
+}
+
+void QOleDataObject::releaseQt()
+{
+    data = 0;
+}
+
+const QMimeData *QOleDataObject::mimeData() const
+{
+    return data;
+}
+
+DWORD QOleDataObject::reportedPerformedEffect() const
+{
+    return performedEffect;
+}
+
+//---------------------------------------------------------------------
+//                    IUnknown Methods
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv)
+{
+    if (iid == IID_IUnknown || iid == IID_IDataObject) {
+        *ppv = this;
+        AddRef();
+        return NOERROR;
+    }
+    *ppv = NULL;
+    return ResultFromScode(E_NOINTERFACE);
+}
+
+STDMETHODIMP_(ULONG)
+QOleDataObject::AddRef(void)
+{
+    return ++m_refs;
+}
+
+STDMETHODIMP_(ULONG)
+QOleDataObject::Release(void)
+{
+    if (--m_refs == 0) {
+        releaseQt();
+        delete this;
+        return 0;
+    }
+    return m_refs;
+}
+
+//---------------------------------------------------------------------
+//                    IDataObject Methods
+//
+// The following methods are NOT supported for data transfer using the
+// clipboard or drag-drop:
+//
+//      IDataObject::SetData    -- return E_NOTIMPL
+//      IDataObject::DAdvise    -- return OLE_E_ADVISENOTSUPPORTED
+//                 ::DUnadvise
+//                 ::EnumDAdvise
+//      IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
+//                     (NOTE: must set pformatetcOut->ptd = NULL)
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)");
+#ifndef Q_OS_WINCE
+    wchar_t buf[256] = {0};
+    GetClipboardFormatName(pformatetc->cfFormat, buf, 255);
+    qDebug("CF = %d : %s", pformatetc->cfFormat, QString::fromWCharArray(buf));
+#endif
+#endif
+
+    if (!data)
+        return ResultFromScode(DATA_E_FORMATETC);
+
+    QWindowsMime *converter = QWindowsMime::converterFromMime(*pformatetc, data);
+
+    if (converter && converter->convertFromMime(*pformatetc, data, pmedium))
+        return ResultFromScode(S_OK);
+    else
+        return ResultFromScode(DATA_E_FORMATETC);
+}
+
+STDMETHODIMP
+QOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
+{
+    return ResultFromScode(DATA_E_FORMATETC);
+}
+
+STDMETHODIMP
+QOleDataObject::QueryGetData(LPFORMATETC pformatetc)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDataObject::QueryGetData(LPFORMATETC pformatetc)");
+#endif
+
+    if (!data)
+        return ResultFromScode(DATA_E_FORMATETC);
+
+    if (QWindowsMime::converterFromMime(*pformatetc, data))
+        return ResultFromScode(S_OK);
+    return ResultFromScode(S_FALSE);
+}
+
+STDMETHODIMP
+QOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
+{
+    pformatetcOut->ptd = NULL;
+    return ResultFromScode(E_NOTIMPL);
+}
+
+STDMETHODIMP
+QOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
+{
+    if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
+        DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal);
+        performedEffect = *val;
+        GlobalUnlock(pMedium->hGlobal);
+        if (fRelease)
+            ReleaseStgMedium(pMedium);
+        return ResultFromScode(S_OK);
+    }
+    return ResultFromScode(E_NOTIMPL);
+}
+
+
+STDMETHODIMP
+QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)");
+#endif
+
+    if (!data)
+        return ResultFromScode(DATA_E_FORMATETC);
+
+    SCODE sc = S_OK;
+
+    QVector<FORMATETC> fmtetcs;
+    if (dwDirection == DATADIR_GET) {
+        fmtetcs = QWindowsMime::allFormatsForMime(data);
+    } else {
+        FORMATETC formatetc;
+        formatetc.cfFormat = CF_PERFORMEDDROPEFFECT;
+        formatetc.dwAspect = DVASPECT_CONTENT;
+        formatetc.lindex = -1;
+        formatetc.ptd = NULL;
+        formatetc.tymed = TYMED_HGLOBAL;
+        fmtetcs.append(formatetc);
+    }
+
+    QOleEnumFmtEtc *enumFmtEtc = new QOleEnumFmtEtc(fmtetcs);
+    *ppenumFormatEtc = enumFmtEtc;
+    if (enumFmtEtc->isNull()) {
+        delete enumFmtEtc;
+        *ppenumFormatEtc = NULL;
+        sc = E_OUTOFMEMORY;
+    }
+
+    return ResultFromScode(sc);
+}
+
+STDMETHODIMP
+QOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
+                       LPADVISESINK, DWORD FAR*)
+{
+    return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+
+STDMETHODIMP
+QOleDataObject::DUnadvise(DWORD)
+{
+    return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+STDMETHODIMP
+QOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
+{
+    return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
+}
+
+#endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD
+
+#ifndef QT_NO_DRAGANDDROP
+
+//#define QDND_DEBUG
+
+#ifdef QDND_DEBUG
+extern QString dragActionsToString(Qt::DropActions actions);
+#endif
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+Qt::MouseButtons toQtMouseButtons(DWORD keyState)
+{
+    Qt::MouseButtons buttons = Qt::NoButton;
+
+    if (keyState & MK_LBUTTON)
+        buttons |= Qt::LeftButton;
+    if (keyState & MK_RBUTTON)
+        buttons |= Qt::RightButton;
+    if (keyState & MK_MBUTTON)
+        buttons |= Qt::MidButton;
+
+    return buttons;
+}
+
+class QOleDropSource : public IDropSource
+{
+public:
+    QOleDropSource();
+    virtual ~QOleDropSource();
+
+    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:
+    Qt::MouseButtons currentButtons;
+    Qt::DropAction currentAction;
+    QMap <Qt::DropAction, QCursor> cursors;
+
+    ULONG m_refs;
+};
+
+
+QOleDropSource::QOleDropSource()
+{
+    currentButtons = Qt::NoButton;
+    m_refs = 1;
+    currentAction = Qt::IgnoreAction;
+}
+
+QOleDropSource::~QOleDropSource()
+{
+}
+
+void QOleDropSource::createCursors()
+{
+    QDragManager *manager = QDragManager::self();
+    if (manager && manager->object
+        && (!manager->object->pixmap().isNull()
+        || manager->hasCustomDragCursors())) {
+        QPixmap pm = manager->object->pixmap();
+        QList<Qt::DropAction> actions;
+        actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
+        if (!manager->object->pixmap().isNull())
+            actions << Qt::IgnoreAction;
+        QPoint hotSpot = manager->object->hotSpot();
+        for (int cnum = 0; cnum < actions.size(); ++cnum) {
+            QPixmap cpm = manager->dragCursor(actions.at(cnum));
+            int w = cpm.width();
+            int h = cpm.height();
+
+            if (!pm.isNull()) {
+                int x1 = qMin(-hotSpot.x(), 0);
+                int x2 = qMax(pm.width() - hotSpot.x(), cpm.width());
+                int y1 = qMin(-hotSpot.y(), 0);
+                int y2 = qMax(pm.height() - hotSpot.y(), cpm.height());
+
+                w = x2 - x1 + 1;
+                h = y2 - y1 + 1;
+            }
+
+            QRect srcRect = pm.rect();
+            QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
+            QPoint newHotSpot = hotSpot;
+
+#if defined(Q_OS_WINCE)
+            // Limited cursor size
+            int reqw = GetSystemMetrics(SM_CXCURSOR);
+            int reqh = GetSystemMetrics(SM_CYCURSOR);
+
+            QPoint hotspotInPM = newHotSpot - pmDest;
+            if (reqw < w) {
+                // Not wide enough - move objectpm right
+                qreal r = qreal(newHotSpot.x()) / w;
+                newHotSpot = QPoint(int(r * reqw), newHotSpot.y());
+                if (newHotSpot.x() + cpm.width() > reqw)
+                    newHotSpot.setX(reqw - cpm.width());
+
+                srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height()));
+            }
+            if (reqh < h) {
+                qreal r = qreal(newHotSpot.y()) / h;
+                newHotSpot = QPoint(newHotSpot.x(), int(r * reqh));
+                if (newHotSpot.y() + cpm.height() > reqh)
+                    newHotSpot.setY(reqh - cpm.height());
+
+                srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh));
+            }
+            // Always use system cursor size
+            w = reqw;
+            h = reqh;
+#endif
+
+            QPixmap newCursor(w, h);
+            if (!pm.isNull()) {
+                newCursor.fill(QColor(0, 0, 0, 0));
+                QPainter p(&newCursor);
+                p.drawPixmap(pmDest, pm, srcRect);
+                p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm);
+            } else {
+                newCursor = cpm;
+            }
+
+#ifndef QT_NO_CURSOR
+            cursors[actions.at(cnum)] = QCursor(newCursor, pm.isNull() ? 0 : qMax(0,newHotSpot.x()),
+                                                pm.isNull() ? 0 : qMax(0,newHotSpot.y()));
+#endif
+        }
+    }
+}
+
+
+
+//---------------------------------------------------------------------
+//                    IUnknown Methods
+//---------------------------------------------------------------------
+
+
+STDMETHODIMP
+QOleDropSource::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)
+QOleDropSource::AddRef(void)
+{
+    return ++m_refs;
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropSource::Release(void)
+{
+    if(--m_refs == 0)
+    {
+      delete this;
+      return 0;
+    }
+    return m_refs;
+}
+
+static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState)
+{
+    Qt::MouseButtons result;
+    if (grfKeyState & MK_LBUTTON)
+        result |= Qt::LeftButton;
+    if (grfKeyState & MK_MBUTTON)
+        result |= Qt::MidButton;
+    if (grfKeyState & MK_RBUTTON)
+        result |= Qt::RightButton;
+    if (grfKeyState & MK_XBUTTON1)
+        result |= Qt::XButton1;
+    if (grfKeyState & MK_XBUTTON2)
+        result |= Qt::XButton2;
+    return result;
+}
+
+//---------------------------------------------------------------------
+//                    IDropSource Methods
+//---------------------------------------------------------------------
+STDMETHODIMP
+QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDropSource::QueryContinueDrag(fEscapePressed %d, grfKeyState %d)", fEscapePressed, grfKeyState);
+#endif
+
+    if (fEscapePressed) {
+        return ResultFromScode(DRAGDROP_S_CANCEL);
+    } else if (!(grfKeyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))) {
+        return ResultFromScode(DRAGDROP_S_DROP);
+    } else {
+#if defined(Q_OS_WINCE)
+        // grfKeyState is broken on CE, therefore need to check
+        // the state manually
+        if ((GetAsyncKeyState(VK_LBUTTON) == 0) &&
+            (GetAsyncKeyState(VK_MBUTTON) == 0) &&
+            (GetAsyncKeyState(VK_RBUTTON) == 0)) {
+            return ResultFromScode(DRAGDROP_S_DROP);
+        }
+#else
+        if (currentButtons == Qt::NoButton) {
+            currentButtons = keystate_to_mousebutton(grfKeyState);
+        } else {
+            Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState);
+            if (!(currentButtons & buttons))
+                return ResultFromScode(DRAGDROP_S_DROP);
+        }
+#endif
+        QApplication::processEvents();
+        return NOERROR;
+    }
+}
+
+STDMETHODIMP
+QOleDropSource::GiveFeedback(DWORD dwEffect)
+{
+    Qt::DropAction action = translateToQDragDropAction(dwEffect);
+
+#ifdef QDND_DEBUG
+    qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)");
+    qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data());
+#endif
+
+    if (currentAction != action) {
+        currentAction = action;
+        QDragManager::self()->emitActionChanged(currentAction);
+    }
+
+    if (cursors.contains(currentAction)) {
+#ifndef QT_NO_CURSOR
+        SetCursor(cursors[currentAction].handle());
+#endif
+        return ResultFromScode(S_OK);
+    }
+
+    return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
+}
+
+//---------------------------------------------------------------------
+//                    QOleDropTarget
+//---------------------------------------------------------------------
+
+QOleDropTarget::QOleDropTarget(QWidget* w)
+:   widget(w)
+{
+   m_refs = 1;
+}
+
+void QOleDropTarget::releaseQt()
+{
+    widget = 0;
+}
+
+//---------------------------------------------------------------------
+//                    IUnknown Methods
+//---------------------------------------------------------------------
+
+
+STDMETHODIMP
+QOleDropTarget::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)
+QOleDropTarget::AddRef(void)
+{
+    return ++m_refs;
+}
+
+
+STDMETHODIMP_(ULONG)
+QOleDropTarget::Release(void)
+{
+    if(--m_refs == 0)
+    {
+      delete this;
+      return 0;
+    }
+    return m_refs;
+}
+
+//---------------------------------------------------------------------
+//                    IDropTarget Methods
+//---------------------------------------------------------------------
+
+STDMETHODIMP
+QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)");
+#endif
+
+    if (!QApplicationPrivate::tryModalHelper(widget)) {
+        *pdwEffect = DROPEFFECT_NONE;
+        return NOERROR;
+    }
+
+    QDragManager *manager = QDragManager::self();
+    manager->dropData->currentDataObject = pDataObj;
+    manager->dropData->currentDataObject->AddRef();
+    sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect);
+    *pdwEffect = chosenEffect;
+
+    return NOERROR;
+}
+
+void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState,
+                                        POINTL pt, LPDWORD pdwEffect)
+{
+    Q_ASSERT(dragEnterWidget);
+    lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y));
+    lastKeyState = grfKeyState;
+
+    chosenEffect = DROPEFFECT_NONE;
+    currentWidget = dragEnterWidget;
+
+    QDragManager *manager = QDragManager::self();
+    QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+    QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+                      toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+    QApplication::sendEvent(dragEnterWidget, &enterEvent);
+    answerRect = enterEvent.answerRect();
+
+    if (enterEvent.isAccepted()) {
+        chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
+    }
+
+    // Documentation states that a drag move event is sendt immidiatly after
+    // a drag enter event. This will honor widgets overriding dragMoveEvent only:
+    if (enterEvent.isAccepted()) {
+        QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+                                 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+        answerRect = enterEvent.answerRect();
+        moveEvent.setDropAction(enterEvent.dropAction());
+        moveEvent.accept(); // accept by default, since enter event was accepted.
+
+        QApplication::sendEvent(dragEnterWidget, &moveEvent);
+        if (moveEvent.isAccepted()) {
+            answerRect = moveEvent.answerRect();
+            chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
+        } else {
+            chosenEffect = DROPEFFECT_NONE;
+        }
+    }
+
+}
+
+STDMETHODIMP
+QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %d)", grfKeyState, pt.x, pt.y, pdwEffect);
+#endif
+
+    QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+    if (!dragOverWidget)
+        dragOverWidget = widget;
+
+
+    if (!QApplicationPrivate::tryModalHelper(dragOverWidget)
+            || !dragOverWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
+        *pdwEffect = DROPEFFECT_NONE;
+        return NOERROR;
+    }
+
+    QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y));
+    // see if we should compress this event
+    if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) {
+        *pdwEffect = chosenEffect;
+        return NOERROR;
+    }
+
+    if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) {
+        QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
+        // Send drag leave event to the previous drag widget.
+        QDragLeaveEvent dragLeave;
+        if (currentWidget)
+            QApplication::sendEvent(currentWidget, &dragLeave);
+        if (!dragOverWidgetGuard) {
+            dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+            if (!dragOverWidget)
+                dragOverWidget = widget;
+        }
+        // Send drag enter event to the current drag widget.
+        sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect);
+    }
+
+    QDragManager *manager = QDragManager::self();
+    QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+
+    QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+                     toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState));
+
+
+    lastPoint = tmpPoint;
+    lastKeyState = grfKeyState;
+
+    QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+                     toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+    if (chosenEffect != DROPEFFECT_NONE) {
+        if (oldEvent.dropAction() == e.dropAction() &&
+            oldEvent.keyboardModifiers() == e.keyboardModifiers())
+            e.setDropAction(translateToQDragDropAction(chosenEffect));
+        e.accept();
+    }
+    QApplication::sendEvent(dragOverWidget, &e);
+
+    answerRect = e.answerRect();
+    if (e.isAccepted())
+        chosenEffect = translateToWinDragEffects(e.dropAction());
+    else
+        chosenEffect = DROPEFFECT_NONE;
+    *pdwEffect = chosenEffect;
+
+    return NOERROR;
+}
+
+STDMETHODIMP
+QOleDropTarget::DragLeave()
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDropTarget::DragLeave()");
+#endif
+
+    if (!QApplicationPrivate::tryModalHelper(widget)) {
+        return NOERROR;
+    }
+
+    currentWidget = 0;
+    QDragLeaveEvent e;
+    QApplication::sendEvent(widget, &e);
+
+    QDragManager *manager = QDragManager::self();
+
+    if (manager->dropData->currentDataObject) { // Sanity
+        manager->dropData->currentDataObject->Release();
+        manager->dropData->currentDataObject = 0;
+    }
+
+    return NOERROR;
+}
+
+#define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
+
+STDMETHODIMP
+QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
+{
+#ifdef QDND_DEBUG
+    qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState);
+#endif
+
+    QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
+    if (!dropWidget)
+        dropWidget = widget;
+
+    if (!QApplicationPrivate::tryModalHelper(dropWidget)
+            || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
+        *pdwEffect = DROPEFFECT_NONE;
+        return NOERROR;
+    }
+
+    lastPoint = dropWidget->mapFromGlobal(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 |= lastKeyState & KEY_STATE_BUTTON_MASK;
+    lastKeyState = grfKeyState;
+
+    QDragManager *manager = QDragManager::self();
+    QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
+    QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
+                 toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
+    if (chosenEffect != DROPEFFECT_NONE) {
+        e.setDropAction(translateToQDragDropAction(chosenEffect));
+    }
+    QApplication::sendEvent(dropWidget, &e);
+
+    if (chosenEffect != DROPEFFECT_NONE) {
+        e.accept();
+    }
+
+
+    if (e.isAccepted()) {
+        if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
+            if (e.dropAction() == Qt::MoveAction)
+                chosenEffect = DROPEFFECT_MOVE;
+            else
+                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;
+                manager->dropData->currentDataObject->SetData(&format, &medium, true);
+            }
+        } else {
+            chosenEffect = translateToWinDragEffects(e.dropAction());
+        }
+    } else {
+        chosenEffect = DROPEFFECT_NONE;
+    }
+    *pdwEffect = chosenEffect;
+
+
+    if (manager->dropData->currentDataObject) {
+        manager->dropData->currentDataObject->Release();
+        manager->dropData->currentDataObject = 0;
+    }
+
+    return NOERROR;
+
+        // We won't get any mouserelease-event, so manually adjust qApp state:
+///### test this        QApplication::winMouseButtonUp();
+}
+
+//---------------------------------------------------------------------
+//                    QDropData
+//---------------------------------------------------------------------
+
+bool QDropData::hasFormat_sys(const QString &mimeType) const
+{
+    if (!currentDataObject) // Sanity
+        return false;
+
+    return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0;
+}
+
+QStringList QDropData::formats_sys() const
+{
+    QStringList fmts;
+    if (!currentDataObject) // Sanity
+        return fmts;
+
+    fmts = QWindowsMime::allMimesForFormats(currentDataObject);
+
+    return fmts;
+}
+
+QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
+{
+    QVariant result;
+
+    if (!currentDataObject) // Sanity
+        return result;
+
+    QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject);
+
+    if (converter)
+        result = converter->convertToMime(mimeType, currentDataObject, type);
+
+    return result;
+}
+
+Qt::DropAction QDragManager::drag(QDrag *o)
+
+{
+#ifdef QDND_DEBUG
+    qDebug("QDragManager::drag(QDrag *drag)");
+#endif
+
+    if (object == o || !o || !o->d_func()->source)
+        return Qt::IgnoreAction;
+
+    if (object) {
+        cancel();
+        qApp->removeEventFilter(this);
+        beingCancelled = false;
+    }
+
+    object = o;
+
+#ifdef QDND_DEBUG
+    qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data());
+#endif
+
+    dragPrivate()->target = 0;
+
+#ifndef QT_NO_ACCESSIBILITY
+    QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
+#endif
+
+    DWORD resultEffect;
+    QOleDropSource *src = new QOleDropSource();
+    src->createCursors();
+    QOleDataObject *obj = new QOleDataObject(o->mimeData());
+    DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions);
+
+#if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
+    HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect);
+#else
+    HRESULT r = DRAGDROP_S_CANCEL;
+    resultEffect = DROPEFFECT_MOVE;
+#endif
+
+    Qt::DropAction ret = Qt::IgnoreAction;
+    if (r == DRAGDROP_S_DROP) {
+        if (obj->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 {
+        dragPrivate()->target = 0;
+    }
+
+    // clean up
+    obj->releaseQt();
+    obj->Release();        // Will delete obj if refcount becomes 0
+    src->Release();        // Will delete src if refcount becomes 0
+    object = 0;
+    o->setMimeData(0);
+    o->deleteLater();
+
+#ifndef QT_NO_ACCESSIBILITY
+    QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
+#endif
+
+    return ret;
+}
+
+void QDragManager::cancel(bool /* deleteSource */)
+{
+    if (object) {
+        beingCancelled = true;
+        object = 0;
+    }
+
+#ifndef QT_NO_CURSOR
+    // insert cancel code here ######## todo
+
+    if (restoreCursor) {
+        QApplication::restoreOverrideCursor();
+        restoreCursor = false;
+    }
+#endif
+#ifndef QT_NO_ACCESSIBILITY
+    QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
+#endif
+}
+
+void QDragManager::updatePixmap()
+{
+    // not used in windows implementation
+}
+
+bool QDragManager::eventFilter(QObject *, QEvent *)
+{
+    // not used in windows implementation
+    return false;
+}
+
+void QDragManager::timerEvent(QTimerEvent*)
+{
+    // not used in windows implementation
+}
+
+void QDragManager::move(const QPoint &)
+{
+    // not used in windows implementation
+}
+
+void QDragManager::drop()
+{
+    // not used in windows implementation
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_DRAGANDDROP