Alexandre Julliard : shell32: Merge the drag & drop implementation from the Unix shell folder.
Alexandre Julliard
julliard at winehq.org
Fri Sep 10 15:29:45 CDT 2021
Module: wine
Branch: master
Commit: df9c67d19695dddf5ee63d64a84244649748f94c
URL: https://source.winehq.org/git/wine.git/?a=commit;h=df9c67d19695dddf5ee63d64a84244649748f94c
Author: Alexandre Julliard <julliard at 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 at 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;
}
More information about the wine-cvs
mailing list