// Author: Vadim Zeitlin
// Modified by:
// Created:
-// RCS-ID: $Id$
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#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
// get default drop effect for given keyboard flags
static DWORD GetDropEffect(DWORD flags, wxDragResult defaultAction, DWORD pdwEffect);
- DECLARE_NO_COPY_CLASS(wxIDropTarget)
+ wxDECLARE_NO_COPY_CLASS(wxIDropTarget);
};
// ----------------------------------------------------------------------------
// 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->IsAcceptedData(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.
result = wxDragNone;
}
- // we need client coordinates to pass to wxWin functions
- if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
- {
- wxLogLastError(wxT("ScreenToClient"));
+ if ( result != wxDragNone ) {
+ // we need client coordinates to pass to wxWin functions
+ if ( !ScreenToClient(m_hwnd, (POINT *)&pt) )
+ {
+ wxLogLastError(wxT("ScreenToClient"));
+ }
+
+ *pdwEffect = ConvertDragResultToEffect(
+ m_pTarget->OnDragOver(pt.x, pt.y, result)
+ );
+ }
+ else {
+ *pdwEffect = DROPEFFECT_NONE;
}
- *pdwEffect = ConvertDragResultToEffect(
- m_pTarget->OnDragOver(pt.x, pt.y, result)
- );
+ // 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;
}
// first ask the drop target if it wants data
if ( m_pTarget->OnDrop(pt.x, pt.y) ) {
// it does, so give it the data source
- m_pTarget->SetDataSource(pIDataSource);
+ m_pTarget->MSWSetDataSource(pIDataSource);
// and now it has the data
wxDragResult rc = ConvertDragEffectToResult(
// 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
}
// copy the data from the data source to the target data object
bool wxDropTarget::GetData()
{
- wxDataFormat format = GetSupportedFormat(m_pIDataSource);
+ 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;
}
// ----------------------------------------------------------------------------
// we need a data source, so wxIDropTarget gives it to us using this function
-void wxDropTarget::SetDataSource(IDataObject *pIDataSource)
+void wxDropTarget::MSWSetDataSource(IDataObject *pIDataSource)
{
m_pIDataSource = pIDataSource;
}
// determine if we accept data of this type
-bool wxDropTarget::IsAcceptedData(IDataObject *pIDataSource) const
+bool wxDropTarget::MSWIsAcceptedData(IDataObject *pIDataSource) const
{
- return GetSupportedFormat(pIDataSource) != wxDF_INVALID;
+ return MSWGetSupportedFormat(pIDataSource) != wxDF_INVALID;
}
// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------
-wxDataFormat wxDropTarget::GetSupportedFormat(IDataObject *pIDataSource) const
+wxDataFormat wxDropTarget::GetMatchingPair()
+{
+ return MSWGetSupportedFormat( m_pIDataSource );
+}
+
+wxDataFormat wxDropTarget::MSWGetSupportedFormat(IDataObject *pIDataSource) const
{
// this strucutre describes a data of any type (first field will be
// changing) being passed through global memory block.
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
// ----------------------------------------------------------------------------