Module: wine Branch: master Commit: df9c67d19695dddf5ee63d64a84244649748f94c URL: https://source.winehq.org/git/wine.git/?a=commit;h=df9c67d19695dddf5ee63d64a...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Sep 10 18:52:37 2021 +0200
shell32: Merge the drag & drop implementation from the Unix shell folder.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/shell32/shfldr_fs.c | 134 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 100 insertions(+), 34 deletions(-)
diff --git a/dlls/shell32/shfldr_fs.c b/dlls/shell32/shfldr_fs.c index 52bdccd6c38..55d380ffb1d 100644 --- a/dlls/shell32/shfldr_fs.c +++ b/dlls/shell32/shfldr_fs.c @@ -72,11 +72,11 @@ typedef struct { LPWSTR sPathTarget; /* complete path to target used for enumeration and ChangeNotify */
LPITEMIDLIST pidlRoot; /* absolute pidl */ - - UINT cfShellIDList; /* clipboardformat for IDropTarget */ - BOOL fAcceptFmt; /* flag for pending Drop */ + DWORD drop_effects_mask; } IGenericSFImpl;
+static UINT cfShellIDList; + static inline IGenericSFImpl *impl_from_IUnknown(IUnknown *iface) { 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); }
-/************************************************************************** -* registers clipboardformat once -*/ -static void SF_RegisterClipFmt (IGenericSFImpl * This) -{ - TRACE ("(%p)\n", This); - - if (!This->cfShellIDList) { - This->cfShellIDList = RegisterClipboardFormatW (CFSTR_SHELLIDLISTW); - } -} - /************************************************************************** * inner IUnknown */ @@ -136,7 +124,7 @@ static HRESULT WINAPI IUnknown_fnQueryInterface(IUnknown *iface, REFIID riid, vo *ppvObj = &This->ISFHelper_iface; else if (IsEqualIID (riid, &IID_IDropTarget)) { *ppvObj = &This->IDropTarget_iface; - SF_RegisterClipFmt(This); + if (!cfShellIDList) cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLISTW); }
if (*ppvObj) { @@ -1543,22 +1531,42 @@ static ULONG WINAPI ISFDropTarget_Release(IDropTarget *iface) 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 ISFDropTarget_DragEnter (IDropTarget * iface, IDataObject * pDataObject, DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) { - FORMATETC fmt; - 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); - This->fAcceptFmt = IDataObject_QueryGetData (pDataObject, &fmt) == S_OK; - if (This->fAcceptFmt) - *pdwEffect = KeyStateToDropEffect(dwKeyState); - else - *pdwEffect = DROPEFFECT_NONE; + if (!pdwEffect || !pDataObject) + return E_INVALIDARG; + + /* Compute a mask of supported drop-effects for this shellfolder object and the given data + * object. Dropping is only supported on folders, which represent filesystem locations. One + * 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; } @@ -1569,15 +1577,12 @@ ISFDropTarget_DragOver (IDropTarget * iface, DWORD dwKeyState, POINTL pt, { 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) return E_INVALIDARG;
- if (This->fAcceptFmt) - *pdwEffect = KeyStateToDropEffect(dwKeyState); - else - *pdwEffect = DROPEFFECT_NONE; + *pdwEffect = KeyStateToDropEffect(dwKeyState) & This->drop_effects_mask;
return S_OK; } @@ -1586,10 +1591,9 @@ static HRESULT WINAPI ISFDropTarget_DragLeave (IDropTarget * iface) { IGenericSFImpl *This = impl_from_IDropTarget(iface);
- TRACE ("(%p)\n", This); - - This->fAcceptFmt = FALSE; + TRACE("(%p)\n", This);
+ This->drop_effects_mask = DROPEFFECT_NONE; return S_OK; }
@@ -1598,8 +1602,70 @@ ISFDropTarget_Drop (IDropTarget * iface, IDataObject * pDataObject, DWORD dwKeyState, POINTL pt, DWORD * pdwEffect) { IGenericSFImpl *This = impl_from_IDropTarget(iface); + FORMATETC format; + STGMEDIUM medium; + HRESULT hr; + + 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; + }
- FIXME ("(%p) object dropped\n", This); + 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; }