shell32: Merge the drag & drop implementation from the Unix shell folder.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
aef981df62
commit
df9c67d196
|
@ -72,11 +72,11 @@ typedef struct {
|
||||||
LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
|
LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
|
||||||
|
|
||||||
LPITEMIDLIST pidlRoot; /* absolute pidl */
|
LPITEMIDLIST pidlRoot; /* absolute pidl */
|
||||||
|
DWORD drop_effects_mask;
|
||||||
UINT cfShellIDList; /* clipboardformat for IDropTarget */
|
|
||||||
BOOL fAcceptFmt; /* flag for pending Drop */
|
|
||||||
} IGenericSFImpl;
|
} IGenericSFImpl;
|
||||||
|
|
||||||
|
static UINT cfShellIDList;
|
||||||
|
|
||||||
static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
|
static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface)
|
||||||
{
|
{
|
||||||
return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
|
return CONTAINING_RECORD(iface, IGenericSFImpl, IUnknown_inner);
|
||||||
|
@ -102,18 +102,6 @@ static inline IGenericSFImpl *impl_from_ISFHelper(ISFHelper *iface)
|
||||||
return CONTAINING_RECORD(iface, IGenericSFImpl, ISFHelper_iface);
|
return CONTAINING_RECORD(iface, IGenericSFImpl, ISFHelper_iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* registers clipboardformat once
|
|
||||||
*/
|
|
||||||
static void SF_RegisterClipFmt (IGenericSFImpl * This)
|
|
||||||
{
|
|
||||||
TRACE ("(%p)\n", This);
|
|
||||||
|
|
||||||
if (!This->cfShellIDList) {
|
|
||||||
This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
* inner IUnknown
|
* inner IUnknown
|
||||||
*/
|
*/
|
||||||
|
@ -136,7 +124,7 @@ static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, vo
|
||||||
*ppvObj = &This->ISFHelper_iface;
|
*ppvObj = &This->ISFHelper_iface;
|
||||||
else if (IsEqualIID (riid, &IID_IDropTarget)) {
|
else if (IsEqualIID (riid, &IID_IDropTarget)) {
|
||||||
*ppvObj = &This->IDropTarget_iface;
|
*ppvObj = &This->IDropTarget_iface;
|
||||||
SF_RegisterClipFmt(This);
|
if (!cfShellIDList) cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*ppvObj) {
|
if (*ppvObj) {
|
||||||
|
@ -1543,22 +1531,42 @@ static ULONG WINAPI ISFDropTarget_Release(IDropTarget *iface)
|
||||||
return IUnknown_Release(This->outer_unk);
|
return IUnknown_Release(This->outer_unk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
|
||||||
|
#define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
|
||||||
|
|
||||||
static HRESULT WINAPI
|
static HRESULT WINAPI
|
||||||
ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
|
ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject,
|
||||||
DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
|
DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
|
||||||
{
|
{
|
||||||
FORMATETC fmt;
|
|
||||||
|
|
||||||
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
||||||
|
FORMATETC format;
|
||||||
|
STGMEDIUM medium;
|
||||||
|
|
||||||
TRACE ("(%p)->(DataObject=%p)\n", This, pDataObject);
|
TRACE("(%p)->(%p 0x%08x {.x=%d, .y=%d} %p)\n", This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
|
||||||
|
|
||||||
InitFormatEtc (fmt, This->cfShellIDList, TYMED_HGLOBAL);
|
if (!pdwEffect || !pDataObject)
|
||||||
This->fAcceptFmt = IDataObject_QueryGetData (pDataObject, &fmt) == S_OK;
|
return E_INVALIDARG;
|
||||||
if (This->fAcceptFmt)
|
|
||||||
*pdwEffect = KeyStateToDropEffect(dwKeyState);
|
/* Compute a mask of supported drop-effects for this shellfolder object and the given data
|
||||||
else
|
* object. Dropping is only supported on folders, which represent filesystem locations. One
|
||||||
*pdwEffect = DROPEFFECT_NONE;
|
* can't drop on file objects. And the 'move' drop effect is only supported, if the source
|
||||||
|
* folder is not identical to the target folder. */
|
||||||
|
This->drop_effects_mask = DROPEFFECT_NONE;
|
||||||
|
InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
|
||||||
|
if (_ILIsFolder(ILFindLastID(This->pidlRoot)) && /* Only drop to folders, not to files */
|
||||||
|
SUCCEEDED(IDataObject_GetData(pDataObject, &format, &medium))) /* Only ShellIDList format */
|
||||||
|
{
|
||||||
|
LPIDA pidaShellIDList = GlobalLock(medium.u.hGlobal);
|
||||||
|
This->drop_effects_mask |= DROPEFFECT_COPY|DROPEFFECT_LINK;
|
||||||
|
|
||||||
|
if (pidaShellIDList) { /* Files can only be moved between two different folders */
|
||||||
|
if (!ILIsEqual(HIDA_GetPIDLFolder(pidaShellIDList), This->pidlRoot))
|
||||||
|
This->drop_effects_mask |= DROPEFFECT_MOVE;
|
||||||
|
GlobalUnlock(medium.u.hGlobal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -1569,15 +1577,12 @@ ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt,
|
||||||
{
|
{
|
||||||
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
||||||
|
|
||||||
TRACE ("(%p)\n", This);
|
TRACE("(%p)->(0x%08x {.x=%d, .y=%d} %p)\n", This, dwKeyState, pt.x, pt.y, pdwEffect);
|
||||||
|
|
||||||
if (!pdwEffect)
|
if (!pdwEffect)
|
||||||
return E_INVALIDARG;
|
return E_INVALIDARG;
|
||||||
|
|
||||||
if (This->fAcceptFmt)
|
*pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
|
||||||
*pdwEffect = KeyStateToDropEffect(dwKeyState);
|
|
||||||
else
|
|
||||||
*pdwEffect = DROPEFFECT_NONE;
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
@ -1586,10 +1591,9 @@ static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface)
|
||||||
{
|
{
|
||||||
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
||||||
|
|
||||||
TRACE ("(%p)\n", This);
|
TRACE("(%p)\n", This);
|
||||||
|
|
||||||
This->fAcceptFmt = FALSE;
|
|
||||||
|
|
||||||
|
This->drop_effects_mask = DROPEFFECT_NONE;
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1598,8 +1602,70 @@ ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject,
|
||||||
DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
|
DWORD dwKeyState, POINTL pt, DWORD * pdwEffect)
|
||||||
{
|
{
|
||||||
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
IGenericSFImpl *This = impl_from_IDropTarget(iface);
|
||||||
|
FORMATETC format;
|
||||||
|
STGMEDIUM medium;
|
||||||
|
HRESULT hr;
|
||||||
|
|
||||||
FIXME ("(%p) object dropped\n", This);
|
TRACE("(%p)->(%p %d {.x=%d, .y=%d} %p) semi-stub\n",
|
||||||
|
This, pDataObject, dwKeyState, pt.x, pt.y, pdwEffect);
|
||||||
|
|
||||||
|
InitFormatEtc(format, cfShellIDList, TYMED_HGLOBAL);
|
||||||
|
hr = IDataObject_GetData(pDataObject, &format, &medium);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return hr;
|
||||||
|
|
||||||
|
if (medium.tymed == TYMED_HGLOBAL) {
|
||||||
|
IShellFolder *psfSourceFolder, *psfDesktopFolder;
|
||||||
|
LPIDA pidaShellIDList = GlobalLock(medium.u.hGlobal);
|
||||||
|
STRRET strret;
|
||||||
|
UINT i;
|
||||||
|
|
||||||
|
if (!pidaShellIDList)
|
||||||
|
return HRESULT_FROM_WIN32(GetLastError());
|
||||||
|
|
||||||
|
hr = SHGetDesktopFolder(&psfDesktopFolder);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
GlobalUnlock(medium.u.hGlobal);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr = IShellFolder_BindToObject(psfDesktopFolder, HIDA_GetPIDLFolder(pidaShellIDList), NULL,
|
||||||
|
&IID_IShellFolder, (LPVOID*)&psfSourceFolder);
|
||||||
|
IShellFolder_Release(psfDesktopFolder);
|
||||||
|
if (FAILED(hr)) {
|
||||||
|
GlobalUnlock(medium.u.hGlobal);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < pidaShellIDList->cidl; i++) {
|
||||||
|
WCHAR wszSourcePath[MAX_PATH];
|
||||||
|
|
||||||
|
hr = IShellFolder_GetDisplayNameOf(psfSourceFolder, HIDA_GetPIDLItem(pidaShellIDList, i),
|
||||||
|
SHGDN_FORPARSING, &strret);
|
||||||
|
if (FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
hr = StrRetToBufW(&strret, NULL, wszSourcePath, MAX_PATH);
|
||||||
|
if (FAILED(hr))
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (*pdwEffect) {
|
||||||
|
case DROPEFFECT_MOVE:
|
||||||
|
FIXME("Move %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
|
||||||
|
break;
|
||||||
|
case DROPEFFECT_COPY:
|
||||||
|
FIXME("Copy %s to %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
|
||||||
|
break;
|
||||||
|
case DROPEFFECT_LINK:
|
||||||
|
FIXME("Link %s from %s!\n", debugstr_w(wszSourcePath), debugstr_w(This->sPathTarget));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IShellFolder_Release(psfSourceFolder);
|
||||||
|
GlobalUnlock(medium.u.hGlobal);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
|
||||||
return E_NOTIMPL;
|
return E_NOTIMPL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue