ChangeSet ID: 21472 CVSROOT: /opt/cvs-commit Module name: wine Changes by: julliard@winehq.org 2005/11/28 05:03:43
Modified files: dlls/shell32 : shlview.c
Log message: Michael Jung mjung@iss.tu-darmstadt.de Register the shell view itself as the drop target, not it's parent folder. Forward drag&drop method calls to the folder currently under the cursor.
Patch: http://cvs.winehq.org/patch.py?id=21472
Old revision New revision Changes Path 1.120 1.121 +96 -32 wine/dlls/shell32/shlview.c
Index: wine/dlls/shell32/shlview.c diff -u -p wine/dlls/shell32/shlview.c:1.120 wine/dlls/shell32/shlview.c:1.121 --- wine/dlls/shell32/shlview.c:1.120 28 Nov 2005 11: 3:43 -0000 +++ wine/dlls/shell32/shlview.c 28 Nov 2005 11: 3:43 -0000 @@ -100,6 +100,9 @@ typedef struct DWORD dwAspects; DWORD dwAdvf; IAdviseSink *pAdvSink; + IDropTarget* pCurDropTarget; /* The sub-item, which is currently dragged over */ + IDataObject* pCurDataObject; /* The dragged data-object */ + LONG iDragOverItem; /* Dragged over item's index, iff pCurDropTarget != NULL */ } IShellViewImpl;
static const IShellViewVtbl svvt; @@ -190,6 +193,10 @@ IShellView * IShellView_Constructor( ISh if(pFolder) IShellFolder_AddRef(pFolder); IShellFolder_QueryInterface(sv->pSFParent, &IID_IShellFolder2, (LPVOID*)&sv->pSF2Parent);
+ sv->pCurDropTarget = NULL; + sv->pCurDataObject = NULL; + sv->iDragOverItem = 0; + TRACE("(%p)->(%p)\n",sv, pFolder); return (IShellView *) sv; } @@ -671,7 +678,7 @@ static LRESULT ShellView_OnCreate(IShell } }
- if (SUCCEEDED(IShellFolder_CreateViewObject(This->pSFParent, This->hWnd, &IID_IDropTarget, (LPVOID*)&pdt))) + if (SUCCEEDED(IUnknown_QueryInterface((IUnknown*)&This->lpVtbl, &IID_IDropTarget, (LPVOID*)&pdt))) { RegisterDragDrop(This->hWnd, pdt); IDropTarget_Release(pdt); @@ -2169,56 +2176,113 @@ static ULONG WINAPI ISVDropTarget_Releas return IShellFolder_Release((IShellFolder*)This); }
-static HRESULT WINAPI ISVDropTarget_DragEnter( - IDropTarget *iface, - IDataObject *pDataObject, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +/****************************************************************************** + * drag_notify_subitem [Internal] + * + * Figure out the shellfolder object, which is currently under the mouse cursor + * and notify it via the IDropTarget interface. + */ +static HRESULT drag_notify_subitem(IShellViewImpl *This, DWORD grfKeyState, POINTL pt, + DWORD *pdwEffect) { + LVHITTESTINFO htinfo; + LVITEMA lvItem; + LONG lResult; + HRESULT hr; + + /* Map from global to client coordinates and query the index of the listview-item, which is + * currently under the mouse cursor. */ + htinfo.pt.x = pt.x; + htinfo.pt.y = pt.y; + htinfo.flags = LVHT_ONITEM; + MapWindowPoints(NULL, This->hWndList, &htinfo.pt, 1); + lResult = SendMessageW(This->hWndList, LVM_HITTEST, 0, (LPARAM)&htinfo); + + /* If we are still over the previous sub-item, notify it via DragOver and return. */ + if (This->pCurDropTarget && lResult == This->iDragOverItem) + return IDropTarget_DragOver(This->pCurDropTarget, grfKeyState, pt, pdwEffect); + + /* We've left the previous sub-item, notify it via DragLeave and Release it. */ + if (This->pCurDropTarget) { + IDropTarget_DragLeave(This->pCurDropTarget); + IDropTarget_Release(This->pCurDropTarget); + This->pCurDropTarget = NULL; + }
- IShellViewImpl *This = impl_from_IDropTarget(iface); + This->iDragOverItem = lResult; + if (lResult == -1) { + /* We are not above one of the listview's subitems. Bind to the parent folder's + * DropTarget interface. */ + hr = IShellFolder_QueryInterface(This->pSFParent, &IID_IDropTarget, + (LPVOID*)&This->pCurDropTarget); + } else { + /* Query the relative PIDL of the shellfolder object represented by the currently + * dragged over listview-item ... */ + ZeroMemory(&lvItem, sizeof(lvItem)); + lvItem.mask = LVIF_PARAM; + lvItem.iItem = lResult; + ListView_GetItemA(This->hWndList, &lvItem); + + /* ... and bind pCurDropTarget to this folder's IDropTarget interface */ + hr = IShellFolder_BindToObject(This->pSFParent, (LPITEMIDLIST)lvItem.lParam, NULL, + &IID_IDropTarget, (LPVOID*)&This->pCurDropTarget); + }
- FIXME("Stub: This=%p, DataObject=%p\n",This,pDataObject); + /* If anything failed, pCurDropTarget should be NULL now, which ought to be a save state. */ + if (FAILED(hr)) + return hr;
- return E_NOTIMPL; + /* Notify the item just entered via DragEnter. */ + return IDropTarget_DragEnter(This->pCurDropTarget, This->pCurDataObject, grfKeyState, pt, pdwEffect); }
-static HRESULT WINAPI ISVDropTarget_DragOver( - IDropTarget *iface, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +static HRESULT WINAPI ISVDropTarget_DragEnter(IDropTarget *iface, IDataObject *pDataObject, + DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface);
- FIXME("Stub: This=%p\n",This); + /* Get a hold on the data object for later calls to DragEnter on the sub-folders */ + This->pCurDataObject = pDataObject; + IDataObject_AddRef(pDataObject);
- return E_NOTIMPL; + return drag_notify_subitem(This, grfKeyState, pt, pdwEffect); }
-static HRESULT WINAPI ISVDropTarget_DragLeave( - IDropTarget *iface) +static HRESULT WINAPI ISVDropTarget_DragOver(IDropTarget *iface, DWORD grfKeyState, POINTL pt, + DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface); + return drag_notify_subitem(This, grfKeyState, pt, pdwEffect); +}
- FIXME("Stub: This=%p\n",This); +static HRESULT WINAPI ISVDropTarget_DragLeave(IDropTarget *iface) { + IShellViewImpl *This = impl_from_IDropTarget(iface);
- return E_NOTIMPL; + IDropTarget_DragLeave(This->pCurDropTarget); + + IDropTarget_Release(This->pCurDropTarget); + IDataObject_Release(This->pCurDataObject); + This->pCurDataObject = NULL; + This->pCurDropTarget = NULL; + This->iDragOverItem = 0; + + return S_OK; }
-static HRESULT WINAPI ISVDropTarget_Drop( - IDropTarget *iface, - IDataObject* pDataObject, - DWORD grfKeyState, - POINTL pt, - DWORD *pdwEffect) +static HRESULT WINAPI ISVDropTarget_Drop(IDropTarget *iface, IDataObject* pDataObject, + DWORD grfKeyState, POINTL pt, DWORD *pdwEffect) { - IShellViewImpl *This = impl_from_IDropTarget(iface); + IShellViewImpl *This = impl_from_IDropTarget(iface);
- FIXME("Stub: This=%p\n",This); + IDropTarget_Drop(This->pCurDropTarget, pDataObject, grfKeyState, pt, pdwEffect);
- return E_NOTIMPL; + IDropTarget_Release(This->pCurDropTarget); + IDataObject_Release(This->pCurDataObject); + This->pCurDataObject = NULL; + This->pCurDropTarget = NULL; + This->iDragOverItem = 0; + + return S_OK; }
static const IDropTargetVtbl dtvt =