#include "wx/msw/ole/oleutils.h"
+#include <initguid.h>
+
+// Some (very) old SDKs don't define IDropTargetHelper, so define our own
+// version of it here.
+struct wxIDropTargetHelper : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE DragEnter(HWND hwndTarget,
+ IDataObject *pDataObject,
+ POINT *ppt,
+ DWORD dwEffect) = 0;
+ virtual HRESULT STDMETHODCALLTYPE DragLeave() = 0;
+ virtual HRESULT STDMETHODCALLTYPE DragOver(POINT *ppt, DWORD dwEffect) = 0;
+ virtual HRESULT STDMETHODCALLTYPE Drop(IDataObject *pDataObject,
+ POINT *ppt,
+ DWORD dwEffect) = 0;
+ virtual HRESULT STDMETHODCALLTYPE Show(BOOL fShow) = 0;
+};
+
+namespace
+{
+ DEFINE_GUID(wxCLSID_DragDropHelper,
+ 0x4657278A,0x411B,0x11D2,0x83,0x9A,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
+ DEFINE_GUID(wxIID_IDropTargetHelper,
+ 0x4657278B,0x411B,0x11D2,0x83,0x9A,0x00,0xC0,0x4F,0xD9,0x18,0xD0);
+}
+
// ----------------------------------------------------------------------------
// IDropTarget interface: forward all interesting things to wxDropTarget
// (the name is unfortunate, but wx_I_DropTarget is not at all the same thing
virtual ~wxIDropTarget();
// accessors for wxDropTarget
+ HWND GetHWND() const { return m_hwnd; }
void SetHwnd(HWND hwnd) { m_hwnd = hwnd; }
// IDropTarget methods
// Params : [in] DWORD flags kbd & mouse flags as passed to
// IDropTarget methods
// [in] wxDragResult defaultAction the default action of the drop target
-// [in] DWORD pdwEffect the supported actions of the drop
+// [in] DWORD pdwEffect the supported actions of the drop
// source passed to IDropTarget methods
// Notes : We do "move" normally and "copy" if <Ctrl> is pressed,
// which is the standard behaviour (currently there is no
wxLogTrace(wxTRACE_OleCalls, wxT("IDropTarget::DragEnter"));
wxASSERT_MSG( m_pIDataObject == NULL,
- _T("drop target must have data object") );
+ wxT("drop target must have data object") );
// show the list of formats supported by the source data object for the
// debugging purposes, this is quite useful sometimes - please don't remove
FORMATETC fmt;
while ( penumFmt->Next(1, &fmt, NULL) == S_OK )
{
- wxLogDebug(_T("Drop source supports format %s"),
+ wxLogDebug(wxT("Drop source supports format %s"),
wxDataObject::GetFormatName(fmt.cfFormat));
}
}
else
{
- wxLogLastError(_T("IDataObject::EnumFormatEtc"));
+ wxLogLastError(wxT("IDataObject::EnumFormatEtc"));
}
#endif // 0
- if ( !m_pTarget->MSWIsAcceptedData(pIDataSource) ) {
- // we don't accept this kind of data
- *pdwEffect = DROPEFFECT_NONE;
-
- return S_OK;
- }
-
// for use in OnEnter and OnDrag calls
m_pTarget->MSWSetDataSource(pIDataSource);
-
+
// get hold of the data object
m_pIDataObject = pIDataSource;
m_pIDataObject->AddRef();
- // we need client coordinates to pass to wxWin functions
- if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
+ if ( !m_pTarget->MSWIsAcceptedData(pIDataSource) ) {
+ // we don't accept this kind of data
+ *pdwEffect = DROPEFFECT_NONE;
+ }
+ else
{
- wxLogLastError(wxT("ScreenToClient"));
+ // we need client coordinates to pass to wxWin functions
+ if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
+ {
+ wxLogLastError(wxT("ScreenToClient"));
+ }
+
+ // give some visual feedback
+ *pdwEffect = ConvertDragResultToEffect(
+ m_pTarget->OnEnter(pt.x, pt.y, ConvertDragEffectToResult(
+ GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect))
+ )
+ );
}
- // give some visual feedback
- *pdwEffect = ConvertDragResultToEffect(
- m_pTarget->OnEnter(pt.x, pt.y, ConvertDragEffectToResult(
- GetDropEffect(grfKeyState, m_pTarget->GetDefaultAction(), *pdwEffect))
- )
- );
+ // update drag image
+ const wxDragResult res = ConvertDragEffectToResult(*pdwEffect);
+ m_pTarget->MSWUpdateDragImageOnEnter(pt.x, pt.y, res);
+ m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y, res);
return S_OK;
}
+
+
// Name : wxIDropTarget::DragOver
// Purpose : Indicates that the mouse was moved inside the window represented
// by this drop target.
*pdwEffect = DROPEFFECT_NONE;
}
+ // update drag image
+ m_pTarget->MSWUpdateDragImageOnDragOver(pt.x, pt.y,
+ ConvertDragEffectToResult(*pdwEffect));
+
return S_OK;
}
// release the held object
RELEASE_AND_NULL(m_pIDataObject);
+ // update drag image
+ m_pTarget->MSWUpdateDragImageOnLeave();
+
return S_OK;
}
// release the held object
RELEASE_AND_NULL(m_pIDataObject);
+ // update drag image
+ m_pTarget->MSWUpdateDragImageOnData(pt.x, pt.y,
+ ConvertDragEffectToResult(*pdwEffect));
+
return S_OK;
}
// ----------------------------------------------------------------------------
wxDropTarget::wxDropTarget(wxDataObject *dataObj)
- : wxDropTargetBase(dataObj)
+ : wxDropTargetBase(dataObj),
+ m_dropTargetHelper(NULL)
{
// create an IDropTarget implementation which will notify us about d&d
// operations.
// we will need the window handle for coords transformation later
m_pIDropTarget->SetHwnd((HWND)hwnd);
+ MSWInitDragImageSupport();
+
return true;
#endif
}
::CoLockObjectExternal(m_pIDropTarget, FALSE, TRUE);
#endif
+ MSWEndDragImageSupport();
+
+ // remove window reference
m_pIDropTarget->SetHwnd(0);
#endif
}
{
wxDataFormat format = MSWGetSupportedFormat(m_pIDataSource);
if ( format == wxDF_INVALID ) {
- // this is strange because IsAcceptedData() succeeded previously!
- wxFAIL_MSG(wxT("strange - did supported formats list change?"));
-
return false;
}
return n < nFormats ? format : wxFormatInvalid;
}
+// ----------------------------------------------------------------------------
+// drag image functions
+// ----------------------------------------------------------------------------
+
+void
+wxDropTarget::MSWEndDragImageSupport()
+{
+ // release drop target helper
+ if ( m_dropTargetHelper != NULL )
+ {
+ m_dropTargetHelper->Release();
+ m_dropTargetHelper = NULL;
+ }
+}
+
+void
+wxDropTarget::MSWInitDragImageSupport()
+{
+ // Use the default drop target helper to show shell drag images
+ CoCreateInstance(wxCLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
+ wxIID_IDropTargetHelper, (LPVOID*)&m_dropTargetHelper);
+}
+
+void
+wxDropTarget::MSWUpdateDragImageOnData(wxCoord x,
+ wxCoord y,
+ wxDragResult dragResult)
+{
+ // call corresponding event on drop target helper
+ if ( m_dropTargetHelper != NULL )
+ {
+ POINT pt = {x, y};
+ DWORD dwEffect = ConvertDragResultToEffect(dragResult);
+ m_dropTargetHelper->Drop(m_pIDataSource, &pt, dwEffect);
+ }
+}
+
+void
+wxDropTarget::MSWUpdateDragImageOnDragOver(wxCoord x,
+ wxCoord y,
+ wxDragResult dragResult)
+{
+ // call corresponding event on drop target helper
+ if ( m_dropTargetHelper != NULL )
+ {
+ POINT pt = {x, y};
+ DWORD dwEffect = ConvertDragResultToEffect(dragResult);
+ m_dropTargetHelper->DragOver(&pt, dwEffect);
+ }
+}
+
+void
+wxDropTarget::MSWUpdateDragImageOnEnter(wxCoord x,
+ wxCoord y,
+ wxDragResult dragResult)
+{
+ // call corresponding event on drop target helper
+ if ( m_dropTargetHelper != NULL )
+ {
+ POINT pt = {x, y};
+ DWORD dwEffect = ConvertDragResultToEffect(dragResult);
+ m_dropTargetHelper->DragEnter(m_pIDropTarget->GetHWND(), m_pIDataSource, &pt, dwEffect);
+ }
+}
+
+void
+wxDropTarget::MSWUpdateDragImageOnLeave()
+{
+ // call corresponding event on drop target helper
+ if ( m_dropTargetHelper != NULL )
+ {
+ m_dropTargetHelper->DragLeave();
+ }
+}
+
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------