src/gui/kernel/qdnd_win.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qapplication.h"
       
    43 
       
    44 #include "qapplication_p.h"
       
    45 #include "qevent.h"
       
    46 #include "qpainter.h"
       
    47 #include "qwidget.h"
       
    48 #include "qbuffer.h"
       
    49 #include "qdatastream.h"
       
    50 #include "qcursor.h"
       
    51 #include "qt_windows.h"
       
    52 #include <shlobj.h>
       
    53 #ifndef QT_NO_ACCESSIBILITY
       
    54 #include "qaccessible.h"
       
    55 #endif
       
    56 #include "qdnd_p.h"
       
    57 #include "qdebug.h"
       
    58 
       
    59 #if defined(Q_OS_WINCE)
       
    60 #include "qguifunctions_wince.h"
       
    61 #endif
       
    62 
       
    63 // support for xbuttons
       
    64 #ifndef MK_XBUTTON1
       
    65 #define MK_XBUTTON1         0x0020
       
    66 #define MK_XBUTTON2         0x0040
       
    67 #endif
       
    68 
       
    69 QT_BEGIN_NAMESPACE
       
    70 
       
    71 #if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
       
    72 
       
    73 //---------------------------------------------------------------------
       
    74 //                    QOleDataObject Constructor
       
    75 //---------------------------------------------------------------------
       
    76 
       
    77 QOleDataObject::QOleDataObject(QMimeData *mimeData)
       
    78 {
       
    79     m_refs = 1;
       
    80     data = mimeData;
       
    81     CF_PERFORMEDDROPEFFECT = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
       
    82     performedEffect = DROPEFFECT_NONE;
       
    83 }
       
    84 
       
    85 QOleDataObject::~QOleDataObject()
       
    86 {
       
    87 }
       
    88 
       
    89 void QOleDataObject::releaseQt()
       
    90 {
       
    91     data = 0;
       
    92 }
       
    93 
       
    94 const QMimeData *QOleDataObject::mimeData() const
       
    95 {
       
    96     return data;
       
    97 }
       
    98 
       
    99 DWORD QOleDataObject::reportedPerformedEffect() const
       
   100 {
       
   101     return performedEffect;
       
   102 }
       
   103 
       
   104 //---------------------------------------------------------------------
       
   105 //                    IUnknown Methods
       
   106 //---------------------------------------------------------------------
       
   107 
       
   108 STDMETHODIMP
       
   109 QOleDataObject::QueryInterface(REFIID iid, void FAR* FAR* ppv)
       
   110 {
       
   111     if (iid == IID_IUnknown || iid == IID_IDataObject) {
       
   112         *ppv = this;
       
   113         AddRef();
       
   114         return NOERROR;
       
   115     }
       
   116     *ppv = NULL;
       
   117     return ResultFromScode(E_NOINTERFACE);
       
   118 }
       
   119 
       
   120 STDMETHODIMP_(ULONG)
       
   121 QOleDataObject::AddRef(void)
       
   122 {
       
   123     return ++m_refs;
       
   124 }
       
   125 
       
   126 STDMETHODIMP_(ULONG)
       
   127 QOleDataObject::Release(void)
       
   128 {
       
   129     if (--m_refs == 0) {
       
   130         releaseQt();
       
   131         delete this;
       
   132         return 0;
       
   133     }
       
   134     return m_refs;
       
   135 }
       
   136 
       
   137 //---------------------------------------------------------------------
       
   138 //                    IDataObject Methods
       
   139 //
       
   140 // The following methods are NOT supported for data transfer using the
       
   141 // clipboard or drag-drop:
       
   142 //
       
   143 //      IDataObject::SetData    -- return E_NOTIMPL
       
   144 //      IDataObject::DAdvise    -- return OLE_E_ADVISENOTSUPPORTED
       
   145 //                 ::DUnadvise
       
   146 //                 ::EnumDAdvise
       
   147 //      IDataObject::GetCanonicalFormatEtc -- return E_NOTIMPL
       
   148 //                     (NOTE: must set pformatetcOut->ptd = NULL)
       
   149 //---------------------------------------------------------------------
       
   150 
       
   151 STDMETHODIMP
       
   152 QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)
       
   153 {
       
   154 #ifdef QDND_DEBUG
       
   155     qDebug("QOleDataObject::GetData(LPFORMATETC pformatetc, LPSTGMEDIUM pmedium)");
       
   156 #ifndef Q_OS_WINCE
       
   157     wchar_t buf[256] = {0};
       
   158     GetClipboardFormatName(pformatetc->cfFormat, buf, 255);
       
   159     qDebug("CF = %d : %s", pformatetc->cfFormat, QString::fromWCharArray(buf));
       
   160 #endif
       
   161 #endif
       
   162 
       
   163     if (!data)
       
   164         return ResultFromScode(DATA_E_FORMATETC);
       
   165 
       
   166     QWindowsMime *converter = QWindowsMime::converterFromMime(*pformatetc, data);
       
   167 
       
   168     if (converter && converter->convertFromMime(*pformatetc, data, pmedium))
       
   169         return ResultFromScode(S_OK);
       
   170     else
       
   171         return ResultFromScode(DATA_E_FORMATETC);
       
   172 }
       
   173 
       
   174 STDMETHODIMP
       
   175 QOleDataObject::GetDataHere(LPFORMATETC, LPSTGMEDIUM)
       
   176 {
       
   177     return ResultFromScode(DATA_E_FORMATETC);
       
   178 }
       
   179 
       
   180 STDMETHODIMP
       
   181 QOleDataObject::QueryGetData(LPFORMATETC pformatetc)
       
   182 {
       
   183 #ifdef QDND_DEBUG
       
   184     qDebug("QOleDataObject::QueryGetData(LPFORMATETC pformatetc)");
       
   185 #endif
       
   186 
       
   187     if (!data)
       
   188         return ResultFromScode(DATA_E_FORMATETC);
       
   189 
       
   190     if (QWindowsMime::converterFromMime(*pformatetc, data))
       
   191         return ResultFromScode(S_OK);
       
   192     return ResultFromScode(S_FALSE);
       
   193 }
       
   194 
       
   195 STDMETHODIMP
       
   196 QOleDataObject::GetCanonicalFormatEtc(LPFORMATETC, LPFORMATETC pformatetcOut)
       
   197 {
       
   198     pformatetcOut->ptd = NULL;
       
   199     return ResultFromScode(E_NOTIMPL);
       
   200 }
       
   201 
       
   202 STDMETHODIMP
       
   203 QOleDataObject::SetData(LPFORMATETC pFormatetc, STGMEDIUM *pMedium, BOOL fRelease)
       
   204 {
       
   205     if (pFormatetc->cfFormat == CF_PERFORMEDDROPEFFECT && pMedium->tymed == TYMED_HGLOBAL) {
       
   206         DWORD * val = (DWORD*)GlobalLock(pMedium->hGlobal);
       
   207         performedEffect = *val;
       
   208         GlobalUnlock(pMedium->hGlobal);
       
   209         if (fRelease)
       
   210             ReleaseStgMedium(pMedium);
       
   211         return ResultFromScode(S_OK);
       
   212     }
       
   213     return ResultFromScode(E_NOTIMPL);
       
   214 }
       
   215 
       
   216 
       
   217 STDMETHODIMP
       
   218 QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)
       
   219 {
       
   220 #ifdef QDND_DEBUG
       
   221     qDebug("QOleDataObject::EnumFormatEtc(DWORD dwDirection, LPENUMFORMATETC FAR* ppenumFormatEtc)");
       
   222 #endif
       
   223 
       
   224     if (!data)
       
   225         return ResultFromScode(DATA_E_FORMATETC);
       
   226 
       
   227     SCODE sc = S_OK;
       
   228 
       
   229     QVector<FORMATETC> fmtetcs;
       
   230     if (dwDirection == DATADIR_GET) {
       
   231         fmtetcs = QWindowsMime::allFormatsForMime(data);
       
   232     } else {
       
   233         FORMATETC formatetc;
       
   234         formatetc.cfFormat = CF_PERFORMEDDROPEFFECT;
       
   235         formatetc.dwAspect = DVASPECT_CONTENT;
       
   236         formatetc.lindex = -1;
       
   237         formatetc.ptd = NULL;
       
   238         formatetc.tymed = TYMED_HGLOBAL;
       
   239         fmtetcs.append(formatetc);
       
   240     }
       
   241 
       
   242     QOleEnumFmtEtc *enumFmtEtc = new QOleEnumFmtEtc(fmtetcs);
       
   243     *ppenumFormatEtc = enumFmtEtc;
       
   244     if (enumFmtEtc->isNull()) {
       
   245         delete enumFmtEtc;
       
   246         *ppenumFormatEtc = NULL;
       
   247         sc = E_OUTOFMEMORY;
       
   248     }
       
   249 
       
   250     return ResultFromScode(sc);
       
   251 }
       
   252 
       
   253 STDMETHODIMP
       
   254 QOleDataObject::DAdvise(FORMATETC FAR*, DWORD,
       
   255                        LPADVISESINK, DWORD FAR*)
       
   256 {
       
   257     return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
       
   258 }
       
   259 
       
   260 
       
   261 STDMETHODIMP
       
   262 QOleDataObject::DUnadvise(DWORD)
       
   263 {
       
   264     return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
       
   265 }
       
   266 
       
   267 STDMETHODIMP
       
   268 QOleDataObject::EnumDAdvise(LPENUMSTATDATA FAR*)
       
   269 {
       
   270     return ResultFromScode(OLE_E_ADVISENOTSUPPORTED);
       
   271 }
       
   272 
       
   273 #endif // QT_NO_DRAGANDDROP && QT_NO_CLIPBOARD
       
   274 
       
   275 #ifndef QT_NO_DRAGANDDROP
       
   276 
       
   277 //#define QDND_DEBUG
       
   278 
       
   279 #ifdef QDND_DEBUG
       
   280 extern QString dragActionsToString(Qt::DropActions actions);
       
   281 #endif
       
   282 
       
   283 Qt::DropActions translateToQDragDropActions(DWORD pdwEffects)
       
   284 {
       
   285     Qt::DropActions actions = Qt::IgnoreAction;
       
   286     if (pdwEffects & DROPEFFECT_LINK)
       
   287         actions |= Qt::LinkAction;
       
   288     if (pdwEffects & DROPEFFECT_COPY)
       
   289         actions |= Qt::CopyAction;
       
   290     if (pdwEffects & DROPEFFECT_MOVE)
       
   291         actions |= Qt::MoveAction;
       
   292     return actions;
       
   293 }
       
   294 
       
   295 Qt::DropAction translateToQDragDropAction(DWORD pdwEffect)
       
   296 {
       
   297     if (pdwEffect & DROPEFFECT_LINK)
       
   298         return Qt::LinkAction;
       
   299     if (pdwEffect & DROPEFFECT_COPY)
       
   300         return Qt::CopyAction;
       
   301     if (pdwEffect & DROPEFFECT_MOVE)
       
   302         return Qt::MoveAction;
       
   303     return Qt::IgnoreAction;
       
   304 }
       
   305 
       
   306 DWORD translateToWinDragEffects(Qt::DropActions action)
       
   307 {
       
   308     DWORD effect = DROPEFFECT_NONE;
       
   309     if (action & Qt::LinkAction)
       
   310         effect |= DROPEFFECT_LINK;
       
   311     if (action & Qt::CopyAction)
       
   312         effect |= DROPEFFECT_COPY;
       
   313     if (action & Qt::MoveAction)
       
   314         effect |= DROPEFFECT_MOVE;
       
   315     return effect;
       
   316 }
       
   317 
       
   318 Qt::KeyboardModifiers toQtKeyboardModifiers(DWORD keyState)
       
   319 {
       
   320     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
       
   321 
       
   322     if (keyState & MK_SHIFT)
       
   323         modifiers |= Qt::ShiftModifier;
       
   324     if (keyState & MK_CONTROL)
       
   325         modifiers |= Qt::ControlModifier;
       
   326     if (keyState & MK_ALT)
       
   327         modifiers |= Qt::AltModifier;
       
   328 
       
   329     return modifiers;
       
   330 }
       
   331 
       
   332 Qt::MouseButtons toQtMouseButtons(DWORD keyState)
       
   333 {
       
   334     Qt::MouseButtons buttons = Qt::NoButton;
       
   335 
       
   336     if (keyState & MK_LBUTTON)
       
   337         buttons |= Qt::LeftButton;
       
   338     if (keyState & MK_RBUTTON)
       
   339         buttons |= Qt::RightButton;
       
   340     if (keyState & MK_MBUTTON)
       
   341         buttons |= Qt::MidButton;
       
   342 
       
   343     return buttons;
       
   344 }
       
   345 
       
   346 class QOleDropSource : public IDropSource
       
   347 {
       
   348 public:
       
   349     QOleDropSource();
       
   350     virtual ~QOleDropSource();
       
   351 
       
   352     void createCursors();
       
   353 
       
   354     // IUnknown methods
       
   355     STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObj);
       
   356     STDMETHOD_(ULONG,AddRef)(void);
       
   357     STDMETHOD_(ULONG,Release)(void);
       
   358 
       
   359     // IDropSource methods
       
   360     STDMETHOD(QueryContinueDrag)(BOOL fEscapePressed, DWORD grfKeyState);
       
   361     STDMETHOD(GiveFeedback)(DWORD dwEffect);
       
   362 
       
   363 private:
       
   364     Qt::MouseButtons currentButtons;
       
   365     Qt::DropAction currentAction;
       
   366     QMap <Qt::DropAction, QCursor> cursors;
       
   367 
       
   368     ULONG m_refs;
       
   369 };
       
   370 
       
   371 
       
   372 QOleDropSource::QOleDropSource()
       
   373 {
       
   374     currentButtons = Qt::NoButton;
       
   375     m_refs = 1;
       
   376     currentAction = Qt::IgnoreAction;
       
   377 }
       
   378 
       
   379 QOleDropSource::~QOleDropSource()
       
   380 {
       
   381 }
       
   382 
       
   383 void QOleDropSource::createCursors()
       
   384 {
       
   385     QDragManager *manager = QDragManager::self();
       
   386     if (manager && manager->object
       
   387         && (!manager->object->pixmap().isNull()
       
   388         || manager->hasCustomDragCursors())) {
       
   389         QPixmap pm = manager->object->pixmap();
       
   390         QList<Qt::DropAction> actions;
       
   391         actions << Qt::MoveAction << Qt::CopyAction << Qt::LinkAction;
       
   392         if (!manager->object->pixmap().isNull())
       
   393             actions << Qt::IgnoreAction;
       
   394         QPoint hotSpot = manager->object->hotSpot();
       
   395         for (int cnum = 0; cnum < actions.size(); ++cnum) {
       
   396             QPixmap cpm = manager->dragCursor(actions.at(cnum));
       
   397             int w = cpm.width();
       
   398             int h = cpm.height();
       
   399 
       
   400             if (!pm.isNull()) {
       
   401                 int x1 = qMin(-hotSpot.x(), 0);
       
   402                 int x2 = qMax(pm.width() - hotSpot.x(), cpm.width());
       
   403                 int y1 = qMin(-hotSpot.y(), 0);
       
   404                 int y2 = qMax(pm.height() - hotSpot.y(), cpm.height());
       
   405 
       
   406                 w = x2 - x1 + 1;
       
   407                 h = y2 - y1 + 1;
       
   408             }
       
   409 
       
   410             QRect srcRect = pm.rect();
       
   411             QPoint pmDest = QPoint(qMax(0, -hotSpot.x()), qMax(0, -hotSpot.y()));
       
   412             QPoint newHotSpot = hotSpot;
       
   413 
       
   414 #if defined(Q_OS_WINCE)
       
   415             // Limited cursor size
       
   416             int reqw = GetSystemMetrics(SM_CXCURSOR);
       
   417             int reqh = GetSystemMetrics(SM_CYCURSOR);
       
   418 
       
   419             QPoint hotspotInPM = newHotSpot - pmDest;
       
   420             if (reqw < w) {
       
   421                 // Not wide enough - move objectpm right
       
   422                 qreal r = qreal(newHotSpot.x()) / w;
       
   423                 newHotSpot = QPoint(int(r * reqw), newHotSpot.y());
       
   424                 if (newHotSpot.x() + cpm.width() > reqw)
       
   425                     newHotSpot.setX(reqw - cpm.width());
       
   426 
       
   427                 srcRect = QRect(QPoint(hotspotInPM.x() - newHotSpot.x(), srcRect.top()), QSize(reqw, srcRect.height()));
       
   428             }
       
   429             if (reqh < h) {
       
   430                 qreal r = qreal(newHotSpot.y()) / h;
       
   431                 newHotSpot = QPoint(newHotSpot.x(), int(r * reqh));
       
   432                 if (newHotSpot.y() + cpm.height() > reqh)
       
   433                     newHotSpot.setY(reqh - cpm.height());
       
   434 
       
   435                 srcRect = QRect(QPoint(srcRect.left(), hotspotInPM.y() - newHotSpot.y()), QSize(srcRect.width(), reqh));
       
   436             }
       
   437             // Always use system cursor size
       
   438             w = reqw;
       
   439             h = reqh;
       
   440 #endif
       
   441 
       
   442             QPixmap newCursor(w, h);
       
   443             if (!pm.isNull()) {
       
   444                 newCursor.fill(QColor(0, 0, 0, 0));
       
   445                 QPainter p(&newCursor);
       
   446                 p.drawPixmap(pmDest, pm, srcRect);
       
   447                 p.drawPixmap(qMax(0,newHotSpot.x()),qMax(0,newHotSpot.y()),cpm);
       
   448             } else {
       
   449                 newCursor = cpm;
       
   450             }
       
   451 
       
   452 #ifndef QT_NO_CURSOR
       
   453             cursors[actions.at(cnum)] = QCursor(newCursor, pm.isNull() ? 0 : qMax(0,newHotSpot.x()),
       
   454                                                 pm.isNull() ? 0 : qMax(0,newHotSpot.y()));
       
   455 #endif
       
   456         }
       
   457     }
       
   458 }
       
   459 
       
   460 
       
   461 
       
   462 //---------------------------------------------------------------------
       
   463 //                    IUnknown Methods
       
   464 //---------------------------------------------------------------------
       
   465 
       
   466 
       
   467 STDMETHODIMP
       
   468 QOleDropSource::QueryInterface(REFIID iid, void FAR* FAR* ppv)
       
   469 {
       
   470     if(iid == IID_IUnknown || iid == IID_IDropSource)
       
   471     {
       
   472       *ppv = this;
       
   473       ++m_refs;
       
   474       return NOERROR;
       
   475     }
       
   476     *ppv = NULL;
       
   477     return ResultFromScode(E_NOINTERFACE);
       
   478 }
       
   479 
       
   480 
       
   481 STDMETHODIMP_(ULONG)
       
   482 QOleDropSource::AddRef(void)
       
   483 {
       
   484     return ++m_refs;
       
   485 }
       
   486 
       
   487 
       
   488 STDMETHODIMP_(ULONG)
       
   489 QOleDropSource::Release(void)
       
   490 {
       
   491     if(--m_refs == 0)
       
   492     {
       
   493       delete this;
       
   494       return 0;
       
   495     }
       
   496     return m_refs;
       
   497 }
       
   498 
       
   499 static inline Qt::MouseButtons keystate_to_mousebutton(DWORD grfKeyState)
       
   500 {
       
   501     Qt::MouseButtons result;
       
   502     if (grfKeyState & MK_LBUTTON)
       
   503         result |= Qt::LeftButton;
       
   504     if (grfKeyState & MK_MBUTTON)
       
   505         result |= Qt::MidButton;
       
   506     if (grfKeyState & MK_RBUTTON)
       
   507         result |= Qt::RightButton;
       
   508     if (grfKeyState & MK_XBUTTON1)
       
   509         result |= Qt::XButton1;
       
   510     if (grfKeyState & MK_XBUTTON2)
       
   511         result |= Qt::XButton2;
       
   512     return result;
       
   513 }
       
   514 
       
   515 //---------------------------------------------------------------------
       
   516 //                    IDropSource Methods
       
   517 //---------------------------------------------------------------------
       
   518 STDMETHODIMP
       
   519 QOleDropSource::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
       
   520 {
       
   521 #ifdef QDND_DEBUG
       
   522     qDebug("QOleDropSource::QueryContinueDrag(fEscapePressed %d, grfKeyState %d)", fEscapePressed, grfKeyState);
       
   523 #endif
       
   524 
       
   525     if (fEscapePressed) {
       
   526         return ResultFromScode(DRAGDROP_S_CANCEL);
       
   527     } else if (!(grfKeyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON))) {
       
   528         return ResultFromScode(DRAGDROP_S_DROP);
       
   529     } else {
       
   530 #if defined(Q_OS_WINCE)
       
   531         // grfKeyState is broken on CE, therefore need to check
       
   532         // the state manually
       
   533         if ((GetAsyncKeyState(VK_LBUTTON) == 0) &&
       
   534             (GetAsyncKeyState(VK_MBUTTON) == 0) &&
       
   535             (GetAsyncKeyState(VK_RBUTTON) == 0)) {
       
   536             return ResultFromScode(DRAGDROP_S_DROP);
       
   537         }
       
   538 #else
       
   539         if (currentButtons == Qt::NoButton) {
       
   540             currentButtons = keystate_to_mousebutton(grfKeyState);
       
   541         } else {
       
   542             Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState);
       
   543             if (!(currentButtons & buttons))
       
   544                 return ResultFromScode(DRAGDROP_S_DROP);
       
   545         }
       
   546 #endif
       
   547         QApplication::processEvents();
       
   548         return NOERROR;
       
   549     }
       
   550 }
       
   551 
       
   552 STDMETHODIMP
       
   553 QOleDropSource::GiveFeedback(DWORD dwEffect)
       
   554 {
       
   555     Qt::DropAction action = translateToQDragDropAction(dwEffect);
       
   556 
       
   557 #ifdef QDND_DEBUG
       
   558     qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)");
       
   559     qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data());
       
   560 #endif
       
   561 
       
   562     if (currentAction != action) {
       
   563         currentAction = action;
       
   564         QDragManager::self()->emitActionChanged(currentAction);
       
   565     }
       
   566 
       
   567     if (cursors.contains(currentAction)) {
       
   568 #ifndef QT_NO_CURSOR
       
   569         SetCursor(cursors[currentAction].handle());
       
   570 #endif
       
   571         return ResultFromScode(S_OK);
       
   572     }
       
   573 
       
   574     return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
       
   575 }
       
   576 
       
   577 //---------------------------------------------------------------------
       
   578 //                    QOleDropTarget
       
   579 //---------------------------------------------------------------------
       
   580 
       
   581 QOleDropTarget::QOleDropTarget(QWidget* w)
       
   582 :   widget(w)
       
   583 {
       
   584    m_refs = 1;
       
   585 }
       
   586 
       
   587 void QOleDropTarget::releaseQt()
       
   588 {
       
   589     widget = 0;
       
   590 }
       
   591 
       
   592 //---------------------------------------------------------------------
       
   593 //                    IUnknown Methods
       
   594 //---------------------------------------------------------------------
       
   595 
       
   596 
       
   597 STDMETHODIMP
       
   598 QOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv)
       
   599 {
       
   600     if(iid == IID_IUnknown || iid == IID_IDropTarget)
       
   601     {
       
   602       *ppv = this;
       
   603       AddRef();
       
   604       return NOERROR;
       
   605     }
       
   606     *ppv = NULL;
       
   607     return ResultFromScode(E_NOINTERFACE);
       
   608 }
       
   609 
       
   610 
       
   611 STDMETHODIMP_(ULONG)
       
   612 QOleDropTarget::AddRef(void)
       
   613 {
       
   614     return ++m_refs;
       
   615 }
       
   616 
       
   617 
       
   618 STDMETHODIMP_(ULONG)
       
   619 QOleDropTarget::Release(void)
       
   620 {
       
   621     if(--m_refs == 0)
       
   622     {
       
   623       delete this;
       
   624       return 0;
       
   625     }
       
   626     return m_refs;
       
   627 }
       
   628 
       
   629 //---------------------------------------------------------------------
       
   630 //                    IDropTarget Methods
       
   631 //---------------------------------------------------------------------
       
   632 
       
   633 STDMETHODIMP
       
   634 QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
       
   635 {
       
   636 #ifdef QDND_DEBUG
       
   637     qDebug("QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)");
       
   638 #endif
       
   639 
       
   640     if (!QApplicationPrivate::tryModalHelper(widget)) {
       
   641         *pdwEffect = DROPEFFECT_NONE;
       
   642         return NOERROR;
       
   643     }
       
   644 
       
   645     QDragManager *manager = QDragManager::self();
       
   646     manager->dropData->currentDataObject = pDataObj;
       
   647     manager->dropData->currentDataObject->AddRef();
       
   648     sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect);
       
   649     *pdwEffect = chosenEffect;
       
   650 
       
   651     return NOERROR;
       
   652 }
       
   653 
       
   654 void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState,
       
   655                                         POINTL pt, LPDWORD pdwEffect)
       
   656 {
       
   657     Q_ASSERT(dragEnterWidget);
       
   658     lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y));
       
   659     lastKeyState = grfKeyState;
       
   660 
       
   661     chosenEffect = DROPEFFECT_NONE;
       
   662     currentWidget = dragEnterWidget;
       
   663 
       
   664     QDragManager *manager = QDragManager::self();
       
   665     QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
       
   666     QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
       
   667                       toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
       
   668     QApplication::sendEvent(dragEnterWidget, &enterEvent);
       
   669     answerRect = enterEvent.answerRect();
       
   670 
       
   671     if (enterEvent.isAccepted()) {
       
   672         chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
       
   673     }
       
   674 
       
   675     // Documentation states that a drag move event is sendt immidiatly after
       
   676     // a drag enter event. This will honor widgets overriding dragMoveEvent only:
       
   677     if (enterEvent.isAccepted()) {
       
   678         QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
       
   679                                  toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
       
   680         answerRect = enterEvent.answerRect();
       
   681         moveEvent.setDropAction(enterEvent.dropAction());
       
   682         moveEvent.accept(); // accept by default, since enter event was accepted.
       
   683 
       
   684         QApplication::sendEvent(dragEnterWidget, &moveEvent);
       
   685         if (moveEvent.isAccepted()) {
       
   686             answerRect = moveEvent.answerRect();
       
   687             chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
       
   688         } else {
       
   689             chosenEffect = DROPEFFECT_NONE;
       
   690         }
       
   691     }
       
   692 
       
   693 }
       
   694 
       
   695 STDMETHODIMP
       
   696 QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
       
   697 {
       
   698 #ifdef QDND_DEBUG
       
   699     qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %d)", grfKeyState, pt.x, pt.y, pdwEffect);
       
   700 #endif
       
   701 
       
   702     QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
       
   703     if (!dragOverWidget)
       
   704         dragOverWidget = widget;
       
   705 
       
   706 
       
   707     if (!QApplicationPrivate::tryModalHelper(dragOverWidget)
       
   708             || !dragOverWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
       
   709         *pdwEffect = DROPEFFECT_NONE;
       
   710         return NOERROR;
       
   711     }
       
   712 
       
   713     QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y));
       
   714     // see if we should compress this event
       
   715     if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) {
       
   716         *pdwEffect = chosenEffect;
       
   717         return NOERROR;
       
   718     }
       
   719 
       
   720     if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) {
       
   721         QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
       
   722         // Send drag leave event to the previous drag widget.
       
   723         QDragLeaveEvent dragLeave;
       
   724         if (currentWidget)
       
   725             QApplication::sendEvent(currentWidget, &dragLeave);
       
   726         if (!dragOverWidgetGuard) {
       
   727             dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
       
   728             if (!dragOverWidget)
       
   729                 dragOverWidget = widget;
       
   730         }
       
   731         // Send drag enter event to the current drag widget.
       
   732         sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect);
       
   733     }
       
   734 
       
   735     QDragManager *manager = QDragManager::self();
       
   736     QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
       
   737 
       
   738     QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
       
   739                      toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState));
       
   740 
       
   741 
       
   742     lastPoint = tmpPoint;
       
   743     lastKeyState = grfKeyState;
       
   744 
       
   745     QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
       
   746                      toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
       
   747     if (chosenEffect != DROPEFFECT_NONE) {
       
   748         if (oldEvent.dropAction() == e.dropAction() &&
       
   749             oldEvent.keyboardModifiers() == e.keyboardModifiers())
       
   750             e.setDropAction(translateToQDragDropAction(chosenEffect));
       
   751         e.accept();
       
   752     }
       
   753     QApplication::sendEvent(dragOverWidget, &e);
       
   754 
       
   755     answerRect = e.answerRect();
       
   756     if (e.isAccepted())
       
   757         chosenEffect = translateToWinDragEffects(e.dropAction());
       
   758     else
       
   759         chosenEffect = DROPEFFECT_NONE;
       
   760     *pdwEffect = chosenEffect;
       
   761 
       
   762     return NOERROR;
       
   763 }
       
   764 
       
   765 STDMETHODIMP
       
   766 QOleDropTarget::DragLeave()
       
   767 {
       
   768 #ifdef QDND_DEBUG
       
   769     qDebug("QOleDropTarget::DragLeave()");
       
   770 #endif
       
   771 
       
   772     if (!QApplicationPrivate::tryModalHelper(widget)) {
       
   773         return NOERROR;
       
   774     }
       
   775 
       
   776     currentWidget = 0;
       
   777     QDragLeaveEvent e;
       
   778     QApplication::sendEvent(widget, &e);
       
   779 
       
   780     QDragManager *manager = QDragManager::self();
       
   781 
       
   782     if (manager->dropData->currentDataObject) { // Sanity
       
   783         manager->dropData->currentDataObject->Release();
       
   784         manager->dropData->currentDataObject = 0;
       
   785     }
       
   786 
       
   787     return NOERROR;
       
   788 }
       
   789 
       
   790 #define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
       
   791 
       
   792 STDMETHODIMP
       
   793 QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
       
   794 {
       
   795 #ifdef QDND_DEBUG
       
   796     qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState);
       
   797 #endif
       
   798 
       
   799     QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
       
   800     if (!dropWidget)
       
   801         dropWidget = widget;
       
   802 
       
   803     if (!QApplicationPrivate::tryModalHelper(dropWidget)
       
   804             || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
       
   805         *pdwEffect = DROPEFFECT_NONE;
       
   806         return NOERROR;
       
   807     }
       
   808 
       
   809     lastPoint = dropWidget->mapFromGlobal(QPoint(pt.x,pt.y));
       
   810     // grfKeyState does not all ways contain button state in the drop so if
       
   811     // it doesn't then use the last known button state;
       
   812     if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
       
   813         grfKeyState |= lastKeyState & KEY_STATE_BUTTON_MASK;
       
   814     lastKeyState = grfKeyState;
       
   815 
       
   816     QDragManager *manager = QDragManager::self();
       
   817     QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
       
   818     QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
       
   819                  toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
       
   820     if (chosenEffect != DROPEFFECT_NONE) {
       
   821         e.setDropAction(translateToQDragDropAction(chosenEffect));
       
   822     }
       
   823     QApplication::sendEvent(dropWidget, &e);
       
   824 
       
   825     if (chosenEffect != DROPEFFECT_NONE) {
       
   826         e.accept();
       
   827     }
       
   828 
       
   829 
       
   830     if (e.isAccepted()) {
       
   831         if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
       
   832             if (e.dropAction() == Qt::MoveAction)
       
   833                 chosenEffect = DROPEFFECT_MOVE;
       
   834             else
       
   835                 chosenEffect = DROPEFFECT_COPY;
       
   836             HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD));
       
   837             if (hData) {
       
   838                 DWORD *moveEffect = (DWORD *)GlobalLock(hData);;
       
   839                 *moveEffect = DROPEFFECT_MOVE;
       
   840                 GlobalUnlock(hData);
       
   841                 STGMEDIUM medium;
       
   842                 memset(&medium, 0, sizeof(STGMEDIUM));
       
   843                 medium.tymed = TYMED_HGLOBAL;
       
   844                 medium.hGlobal = hData;
       
   845                 FORMATETC format;
       
   846                 format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
       
   847                 format.tymed = TYMED_HGLOBAL;
       
   848                 format.ptd = 0;
       
   849                 format.dwAspect = 1;
       
   850                 format.lindex = -1;
       
   851                 manager->dropData->currentDataObject->SetData(&format, &medium, true);
       
   852             }
       
   853         } else {
       
   854             chosenEffect = translateToWinDragEffects(e.dropAction());
       
   855         }
       
   856     } else {
       
   857         chosenEffect = DROPEFFECT_NONE;
       
   858     }
       
   859     *pdwEffect = chosenEffect;
       
   860 
       
   861 
       
   862     if (manager->dropData->currentDataObject) {
       
   863         manager->dropData->currentDataObject->Release();
       
   864         manager->dropData->currentDataObject = 0;
       
   865     }
       
   866 
       
   867     return NOERROR;
       
   868 
       
   869         // We won't get any mouserelease-event, so manually adjust qApp state:
       
   870 ///### test this        QApplication::winMouseButtonUp();
       
   871 }
       
   872 
       
   873 //---------------------------------------------------------------------
       
   874 //                    QDropData
       
   875 //---------------------------------------------------------------------
       
   876 
       
   877 bool QDropData::hasFormat_sys(const QString &mimeType) const
       
   878 {
       
   879     if (!currentDataObject) // Sanity
       
   880         return false;
       
   881 
       
   882     return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0;
       
   883 }
       
   884 
       
   885 QStringList QDropData::formats_sys() const
       
   886 {
       
   887     QStringList fmts;
       
   888     if (!currentDataObject) // Sanity
       
   889         return fmts;
       
   890 
       
   891     fmts = QWindowsMime::allMimesForFormats(currentDataObject);
       
   892 
       
   893     return fmts;
       
   894 }
       
   895 
       
   896 QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
       
   897 {
       
   898     QVariant result;
       
   899 
       
   900     if (!currentDataObject) // Sanity
       
   901         return result;
       
   902 
       
   903     QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject);
       
   904 
       
   905     if (converter)
       
   906         result = converter->convertToMime(mimeType, currentDataObject, type);
       
   907 
       
   908     return result;
       
   909 }
       
   910 
       
   911 Qt::DropAction QDragManager::drag(QDrag *o)
       
   912 
       
   913 {
       
   914 #ifdef QDND_DEBUG
       
   915     qDebug("QDragManager::drag(QDrag *drag)");
       
   916 #endif
       
   917 
       
   918     if (object == o || !o || !o->d_func()->source)
       
   919         return Qt::IgnoreAction;
       
   920 
       
   921     if (object) {
       
   922         cancel();
       
   923         qApp->removeEventFilter(this);
       
   924         beingCancelled = false;
       
   925     }
       
   926 
       
   927     object = o;
       
   928 
       
   929 #ifdef QDND_DEBUG
       
   930     qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data());
       
   931 #endif
       
   932 
       
   933     dragPrivate()->target = 0;
       
   934 
       
   935 #ifndef QT_NO_ACCESSIBILITY
       
   936     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
       
   937 #endif
       
   938 
       
   939     DWORD resultEffect;
       
   940     QOleDropSource *src = new QOleDropSource();
       
   941     src->createCursors();
       
   942     QOleDataObject *obj = new QOleDataObject(o->mimeData());
       
   943     DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions);
       
   944 
       
   945 #if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
       
   946     HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect);
       
   947 #else
       
   948     HRESULT r = DRAGDROP_S_CANCEL;
       
   949     resultEffect = DROPEFFECT_MOVE;
       
   950 #endif
       
   951 
       
   952     Qt::DropAction ret = Qt::IgnoreAction;
       
   953     if (r == DRAGDROP_S_DROP) {
       
   954         if (obj->reportedPerformedEffect() == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
       
   955             ret = Qt::TargetMoveAction;
       
   956             resultEffect = DROPEFFECT_MOVE;
       
   957         } else {
       
   958             ret = translateToQDragDropAction(resultEffect);
       
   959         }
       
   960         // Force it to be a copy if an unsupported operation occurred.
       
   961         // This indicates a bug in the drop target.
       
   962         if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
       
   963             ret = Qt::CopyAction;
       
   964     } else {
       
   965         dragPrivate()->target = 0;
       
   966     }
       
   967 
       
   968     // clean up
       
   969     obj->releaseQt();
       
   970     obj->Release();        // Will delete obj if refcount becomes 0
       
   971     src->Release();        // Will delete src if refcount becomes 0
       
   972     object = 0;
       
   973     o->setMimeData(0);
       
   974     o->deleteLater();
       
   975 
       
   976 #ifndef QT_NO_ACCESSIBILITY
       
   977     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
       
   978 #endif
       
   979 
       
   980     return ret;
       
   981 }
       
   982 
       
   983 void QDragManager::cancel(bool /* deleteSource */)
       
   984 {
       
   985     if (object) {
       
   986         beingCancelled = true;
       
   987         object = 0;
       
   988     }
       
   989 
       
   990 #ifndef QT_NO_CURSOR
       
   991     // insert cancel code here ######## todo
       
   992 
       
   993     if (restoreCursor) {
       
   994         QApplication::restoreOverrideCursor();
       
   995         restoreCursor = false;
       
   996     }
       
   997 #endif
       
   998 #ifndef QT_NO_ACCESSIBILITY
       
   999     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
       
  1000 #endif
       
  1001 }
       
  1002 
       
  1003 void QDragManager::updatePixmap()
       
  1004 {
       
  1005     // not used in windows implementation
       
  1006 }
       
  1007 
       
  1008 bool QDragManager::eventFilter(QObject *, QEvent *)
       
  1009 {
       
  1010     // not used in windows implementation
       
  1011     return false;
       
  1012 }
       
  1013 
       
  1014 void QDragManager::timerEvent(QTimerEvent*)
       
  1015 {
       
  1016     // not used in windows implementation
       
  1017 }
       
  1018 
       
  1019 void QDragManager::move(const QPoint &)
       
  1020 {
       
  1021     // not used in windows implementation
       
  1022 }
       
  1023 
       
  1024 void QDragManager::drop()
       
  1025 {
       
  1026     // not used in windows implementation
       
  1027 }
       
  1028 
       
  1029 QT_END_NAMESPACE
       
  1030 
       
  1031 #endif // QT_NO_DRAGANDDROP