Fix compilation with QDND_DEBUG.
[qt:qt.git] / src / gui / kernel / qdnd_win.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 QT_ENSURE_STACK_ALIGNED_FOR_SSE 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 ((GetAsyncKeyState(VK_LBUTTON) == 0)
528         && (GetAsyncKeyState(VK_MBUTTON) == 0)
529         && (GetAsyncKeyState(VK_RBUTTON) == 0))    {
530         // grfKeyState is broken on CE & some Windows XP versions,
531         // therefore we need to check the state manually
532         return ResultFromScode(DRAGDROP_S_DROP);
533     } else {
534 #if !defined(Q_OS_WINCE)
535         if (currentButtons == Qt::NoButton) {
536             currentButtons = keystate_to_mousebutton(grfKeyState);
537         } else {
538             Qt::MouseButtons buttons = keystate_to_mousebutton(grfKeyState);
539             if (!(currentButtons & buttons))
540                 return ResultFromScode(DRAGDROP_S_DROP);
541         }
542 #else
543     Q_UNUSED(grfKeyState);
544 #endif
545         QApplication::processEvents();
546         return NOERROR;
547     }
548 }
549
550 QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
551 QOleDropSource::GiveFeedback(DWORD dwEffect)
552 {
553     Qt::DropAction action = translateToQDragDropAction(dwEffect);
554
555 #ifdef QDND_DEBUG
556     qDebug("QOleDropSource::GiveFeedback(DWORD dwEffect)");
557     qDebug("dwEffect = %s", dragActionsToString(action).toLatin1().data());
558 #endif
559
560     if (currentAction != action) {
561         currentAction = action;
562         QDragManager::self()->emitActionChanged(currentAction);
563     }
564
565     if (cursors.contains(currentAction)) {
566 #ifndef QT_NO_CURSOR
567         SetCursor(cursors[currentAction].handle());
568 #endif
569         return ResultFromScode(S_OK);
570     }
571
572     return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
573 }
574
575 //---------------------------------------------------------------------
576 //                    QOleDropTarget
577 //---------------------------------------------------------------------
578
579 QOleDropTarget::QOleDropTarget(QWidget* w)
580 :   widget(w)
581 {
582    m_refs = 1;
583 }
584
585 void QOleDropTarget::releaseQt()
586 {
587     widget = 0;
588 }
589
590 //---------------------------------------------------------------------
591 //                    IUnknown Methods
592 //---------------------------------------------------------------------
593
594
595 STDMETHODIMP
596 QOleDropTarget::QueryInterface(REFIID iid, void FAR* FAR* ppv)
597 {
598     if(iid == IID_IUnknown || iid == IID_IDropTarget)
599     {
600       *ppv = this;
601       AddRef();
602       return NOERROR;
603     }
604     *ppv = NULL;
605     return ResultFromScode(E_NOINTERFACE);
606 }
607
608
609 STDMETHODIMP_(ULONG)
610 QOleDropTarget::AddRef(void)
611 {
612     return ++m_refs;
613 }
614
615
616 STDMETHODIMP_(ULONG)
617 QOleDropTarget::Release(void)
618 {
619     if(--m_refs == 0)
620     {
621       delete this;
622       return 0;
623     }
624     return m_refs;
625 }
626
627 //---------------------------------------------------------------------
628 //                    IDropTarget Methods
629 //---------------------------------------------------------------------
630
631 QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
632 QOleDropTarget::DragEnter(LPDATAOBJECT pDataObj, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
633 {
634 #ifdef QDND_DEBUG
635     qDebug("QOleDropTarget::DragEnter(grfKeyState %d, pt (%d,%d), pdwEffect %lu)",
636            grfKeyState, pt.x, pt.y, *pdwEffect);
637 #endif
638
639     if (!QApplicationPrivate::tryModalHelper(widget)) {
640         *pdwEffect = DROPEFFECT_NONE;
641         return NOERROR;
642     }
643
644     QDragManager *manager = QDragManager::self();
645     manager->dropData->currentDataObject = pDataObj;
646     manager->dropData->currentDataObject->AddRef();
647     sendDragEnterEvent(widget, grfKeyState, pt, pdwEffect);
648     *pdwEffect = chosenEffect;
649
650     return NOERROR;
651 }
652
653 void QOleDropTarget::sendDragEnterEvent(QWidget *dragEnterWidget, DWORD grfKeyState,
654                                         POINTL pt, LPDWORD pdwEffect)
655 {
656     Q_ASSERT(dragEnterWidget);
657     lastPoint = dragEnterWidget->mapFromGlobal(QPoint(pt.x,pt.y));
658     lastKeyState = grfKeyState;
659
660     chosenEffect = DROPEFFECT_NONE;
661     currentWidget = dragEnterWidget;
662
663     QDragManager *manager = QDragManager::self();
664     QMimeData * md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
665     QDragEnterEvent enterEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
666                       toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
667     QApplication::sendEvent(dragEnterWidget, &enterEvent);
668     answerRect = enterEvent.answerRect();
669
670     if (enterEvent.isAccepted()) {
671         chosenEffect = translateToWinDragEffects(enterEvent.dropAction());
672     }
673
674     // Documentation states that a drag move event is sendt immidiatly after
675     // a drag enter event. This will honor widgets overriding dragMoveEvent only:
676     if (enterEvent.isAccepted()) {
677         QDragMoveEvent moveEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
678                                  toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
679         answerRect = enterEvent.answerRect();
680         moveEvent.setDropAction(enterEvent.dropAction());
681         moveEvent.accept(); // accept by default, since enter event was accepted.
682
683         QApplication::sendEvent(dragEnterWidget, &moveEvent);
684         if (moveEvent.isAccepted()) {
685             answerRect = moveEvent.answerRect();
686             chosenEffect = translateToWinDragEffects(moveEvent.dropAction());
687         } else {
688             chosenEffect = DROPEFFECT_NONE;
689         }
690     }
691
692 }
693
694 static inline bool acceptsDrop(const QWidget *w)
695 {
696     return w->testAttribute(Qt::WA_DropSiteRegistered) && w->acceptDrops();
697 }
698
699 QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
700 QOleDropTarget::DragOver(DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
701 {
702 #ifdef QDND_DEBUG
703     qDebug("QOleDropTarget::DragOver(grfKeyState %d, pt (%d,%d), pdwEffect %lu)",
704            grfKeyState, pt.x, pt.y, *pdwEffect);
705 #endif
706
707     QWidget *dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
708     if (!dragOverWidget)
709         dragOverWidget = widget;
710
711
712     if (!QApplicationPrivate::tryModalHelper(dragOverWidget)) {
713         *pdwEffect = DROPEFFECT_NONE;
714         return NOERROR;
715     }
716
717     // Try to find a drop-enabled target in the hierarchy. Go beyond 'widget' in case
718     // it is a native child window which has its own drop site registered (QTBUG-27265).
719     while (dragOverWidget && !dragOverWidget->isWindow() && !acceptsDrop(dragOverWidget))
720         dragOverWidget = dragOverWidget->parentWidget();
721
722     if (!dragOverWidget || !acceptsDrop(dragOverWidget)) {
723         *pdwEffect = DROPEFFECT_NONE;
724         return NOERROR;
725     }
726
727     QPoint tmpPoint = dragOverWidget->mapFromGlobal(QPoint(pt.x, pt.y));
728     // see if we should compress this event
729     if ((tmpPoint == lastPoint || answerRect.contains(tmpPoint)) && lastKeyState == grfKeyState) {
730         *pdwEffect = chosenEffect;
731         return NOERROR;
732     }
733
734     if (!dragOverWidget->internalWinId() && dragOverWidget != currentWidget) {
735         QPointer<QWidget> dragOverWidgetGuard(dragOverWidget);
736         // Send drag leave event to the previous drag widget.
737         QDragLeaveEvent dragLeave;
738         if (currentWidget)
739             QApplication::sendEvent(currentWidget, &dragLeave);
740         if (!dragOverWidgetGuard) {
741             dragOverWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
742             if (!dragOverWidget)
743                 dragOverWidget = widget;
744         }
745         // Send drag enter event to the current drag widget.
746         sendDragEnterEvent(dragOverWidget, grfKeyState, pt, pdwEffect);
747     }
748
749     QDragManager *manager = QDragManager::self();
750     QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
751
752     QDragMoveEvent oldEvent(lastPoint, translateToQDragDropActions(*pdwEffect), md,
753                      toQtMouseButtons(lastKeyState), toQtKeyboardModifiers(lastKeyState));
754
755
756     lastPoint = tmpPoint;
757     lastKeyState = grfKeyState;
758
759     QDragMoveEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
760                      toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
761     if (chosenEffect != DROPEFFECT_NONE) {
762         if (oldEvent.dropAction() == e.dropAction() &&
763             oldEvent.keyboardModifiers() == e.keyboardModifiers())
764             e.setDropAction(translateToQDragDropAction(chosenEffect));
765         e.accept();
766     }
767     QApplication::sendEvent(dragOverWidget, &e);
768
769     answerRect = e.answerRect();
770     if (e.isAccepted())
771         chosenEffect = translateToWinDragEffects(e.dropAction());
772     else
773         chosenEffect = DROPEFFECT_NONE;
774     *pdwEffect = chosenEffect;
775
776     return NOERROR;
777 }
778
779 QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
780 QOleDropTarget::DragLeave()
781 {
782 #ifdef QDND_DEBUG
783     qDebug("QOleDropTarget::DragLeave()");
784 #endif
785
786     if (!QApplicationPrivate::tryModalHelper(widget)) {
787         return NOERROR;
788     }
789
790     currentWidget = 0;
791     QDragLeaveEvent e;
792     QApplication::sendEvent(widget, &e);
793
794     QDragManager *manager = QDragManager::self();
795
796     if (manager->dropData->currentDataObject) { // Sanity
797         manager->dropData->currentDataObject->Release();
798         manager->dropData->currentDataObject = 0;
799     }
800
801     return NOERROR;
802 }
803
804 #define KEY_STATE_BUTTON_MASK (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON)
805
806 QT_ENSURE_STACK_ALIGNED_FOR_SSE STDMETHODIMP
807 QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, DWORD grfKeyState, POINTL pt, LPDWORD pdwEffect)
808 {
809 #ifdef QDND_DEBUG
810     qDebug("QOleDropTarget::Drop(LPDATAOBJECT /*pDataObj*/, grfKeyState %d, POINTL pt, LPDWORD pdwEffect)", grfKeyState);
811 #endif
812
813     QWidget *dropWidget = widget->childAt(widget->mapFromGlobal(QPoint(pt.x, pt.y)));
814     if (!dropWidget)
815         dropWidget = widget;
816
817     if (!QApplicationPrivate::tryModalHelper(dropWidget)
818             || !dropWidget->testAttribute(Qt::WA_DropSiteRegistered)) {
819         *pdwEffect = DROPEFFECT_NONE;
820         return NOERROR;
821     }
822
823     lastPoint = dropWidget->mapFromGlobal(QPoint(pt.x,pt.y));
824     // grfKeyState does not all ways contain button state in the drop so if
825     // it doesn't then use the last known button state;
826     if ((grfKeyState & KEY_STATE_BUTTON_MASK) == 0)
827         grfKeyState |= lastKeyState & KEY_STATE_BUTTON_MASK;
828     lastKeyState = grfKeyState;
829
830     QDragManager *manager = QDragManager::self();
831     QMimeData *md = manager->source() ? manager->dragPrivate()->data : manager->dropData;
832     QDropEvent e(lastPoint, translateToQDragDropActions(*pdwEffect), md,
833                  toQtMouseButtons(grfKeyState), toQtKeyboardModifiers(grfKeyState));
834     if (chosenEffect != DROPEFFECT_NONE) {
835         e.setDropAction(translateToQDragDropAction(chosenEffect));
836     }
837     QApplication::sendEvent(dropWidget, &e);
838
839     if (chosenEffect != DROPEFFECT_NONE) {
840         e.accept();
841     }
842
843
844     if (e.isAccepted()) {
845         if (e.dropAction() == Qt::MoveAction || e.dropAction() == Qt::TargetMoveAction) {
846             if (e.dropAction() == Qt::MoveAction)
847                 chosenEffect = DROPEFFECT_MOVE;
848             else
849                 chosenEffect = DROPEFFECT_COPY;
850             HGLOBAL hData = GlobalAlloc(0, sizeof(DWORD));
851             if (hData) {
852                 DWORD *moveEffect = (DWORD *)GlobalLock(hData);;
853                 *moveEffect = DROPEFFECT_MOVE;
854                 GlobalUnlock(hData);
855                 STGMEDIUM medium;
856                 memset(&medium, 0, sizeof(STGMEDIUM));
857                 medium.tymed = TYMED_HGLOBAL;
858                 medium.hGlobal = hData;
859                 FORMATETC format;
860                 format.cfFormat = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
861                 format.tymed = TYMED_HGLOBAL;
862                 format.ptd = 0;
863                 format.dwAspect = 1;
864                 format.lindex = -1;
865                 manager->dropData->currentDataObject->SetData(&format, &medium, true);
866             }
867         } else {
868             chosenEffect = translateToWinDragEffects(e.dropAction());
869         }
870     } else {
871         chosenEffect = DROPEFFECT_NONE;
872     }
873     *pdwEffect = chosenEffect;
874
875
876     if (manager->dropData->currentDataObject) {
877         manager->dropData->currentDataObject->Release();
878         manager->dropData->currentDataObject = 0;
879     }
880
881     return NOERROR;
882
883         // We won't get any mouserelease-event, so manually adjust qApp state:
884 ///### test this        QApplication::winMouseButtonUp();
885 }
886
887 //---------------------------------------------------------------------
888 //                    QDropData
889 //---------------------------------------------------------------------
890
891 bool QDropData::hasFormat_sys(const QString &mimeType) const
892 {
893     if (!currentDataObject) // Sanity
894         return false;
895
896     return QWindowsMime::converterToMime(mimeType, currentDataObject) != 0;
897 }
898
899 QStringList QDropData::formats_sys() const
900 {
901     QStringList fmts;
902     if (!currentDataObject) // Sanity
903         return fmts;
904
905     fmts = QWindowsMime::allMimesForFormats(currentDataObject);
906
907     return fmts;
908 }
909
910 QVariant QDropData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
911 {
912     QVariant result;
913
914     if (!currentDataObject) // Sanity
915         return result;
916
917     QWindowsMime *converter = QWindowsMime::converterToMime(mimeType, currentDataObject);
918
919     if (converter)
920         result = converter->convertToMime(mimeType, currentDataObject, type);
921
922     return result;
923 }
924
925 Qt::DropAction QDragManager::drag(QDrag *o)
926
927 {
928 #ifdef QDND_DEBUG
929     qDebug("QDragManager::drag(QDrag *drag)");
930 #endif
931
932     if (object == o || !o || !o->d_func()->source)
933         return Qt::IgnoreAction;
934
935     if (object) {
936         cancel();
937         qApp->removeEventFilter(this);
938         beingCancelled = false;
939     }
940
941     object = o;
942
943 #ifdef QDND_DEBUG
944     qDebug("actions = %s", dragActionsToString(dragPrivate()->possible_actions).toLatin1().data());
945 #endif
946
947     dragPrivate()->target = 0;
948
949 #ifndef QT_NO_ACCESSIBILITY
950     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropStart);
951 #endif
952
953     DWORD resultEffect;
954     QOleDropSource *src = new QOleDropSource();
955     src->createCursors();
956     QOleDataObject *obj = new QOleDataObject(o->mimeData());
957     DWORD allowedEffects = translateToWinDragEffects(dragPrivate()->possible_actions);
958
959 #if !defined(Q_OS_WINCE) || defined(GWES_ICONCURS)
960     HRESULT r = DoDragDrop(obj, src, allowedEffects, &resultEffect);
961 #else
962     HRESULT r = DRAGDROP_S_CANCEL;
963     resultEffect = DROPEFFECT_MOVE;
964 #endif
965
966     Qt::DropAction ret = Qt::IgnoreAction;
967     if (r == DRAGDROP_S_DROP) {
968         if (obj->reportedPerformedEffect() == DROPEFFECT_MOVE && resultEffect != DROPEFFECT_MOVE) {
969             ret = Qt::TargetMoveAction;
970             resultEffect = DROPEFFECT_MOVE;
971         } else {
972             ret = translateToQDragDropAction(resultEffect);
973         }
974         // Force it to be a copy if an unsupported operation occurred.
975         // This indicates a bug in the drop target.
976         if (resultEffect != DROPEFFECT_NONE && !(resultEffect & allowedEffects))
977             ret = Qt::CopyAction;
978     } else {
979         dragPrivate()->target = 0;
980     }
981
982     // clean up
983     obj->releaseQt();
984     obj->Release();        // Will delete obj if refcount becomes 0
985     src->Release();        // Will delete src if refcount becomes 0
986     object = 0;
987     o->setMimeData(0);
988     o->deleteLater();
989
990 #ifndef QT_NO_ACCESSIBILITY
991     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
992 #endif
993
994     return ret;
995 }
996
997 void QDragManager::cancel(bool /* deleteSource */)
998 {
999     if (object) {
1000         beingCancelled = true;
1001         object = 0;
1002     }
1003
1004 #ifndef QT_NO_CURSOR
1005     // insert cancel code here ######## todo
1006
1007     if (restoreCursor) {
1008         QApplication::restoreOverrideCursor();
1009         restoreCursor = false;
1010     }
1011 #endif
1012 #ifndef QT_NO_ACCESSIBILITY
1013     QAccessible::updateAccessibility(this, 0, QAccessible::DragDropEnd);
1014 #endif
1015 }
1016
1017 void QDragManager::updatePixmap()
1018 {
1019     // not used in windows implementation
1020 }
1021
1022 bool QDragManager::eventFilter(QObject *, QEvent *)
1023 {
1024     // not used in windows implementation
1025     return false;
1026 }
1027
1028 void QDragManager::timerEvent(QTimerEvent*)
1029 {
1030     // not used in windows implementation
1031 }
1032
1033 void QDragManager::move(const QPoint &)
1034 {
1035     // not used in windows implementation
1036 }
1037
1038 void QDragManager::drop()
1039 {
1040     // not used in windows implementation
1041 }
1042
1043 QT_END_NAMESPACE
1044
1045 #endif // QT_NO_DRAGANDDROP