Win32: Implement extended drag & drop API

This commit is contained in:
Florian Albrechtskirchinger 2022-06-17 12:00:32 +02:00
parent d2763ec2a1
commit 2933c00e54
No known key found for this signature in database
GPG Key ID: 19618CE9B2D4BE6D
3 changed files with 178 additions and 66 deletions

View File

@ -458,12 +458,12 @@ static GLFWbool initDragDrop()
}
//_glfw.win32.dropTargetVtbl.QueryInterface = _glfwDropTarget_QueryInterface;
_glfw.win32.dropTargetVtbl.AddRef = (PFN_IDropTarget_AddRef)_glfwDropTarget_AddRef;
_glfw.win32.dropTargetVtbl.Release = (PFN_IDropTarget_Release)_glfwDropTarget_Release;
_glfw.win32.dropTargetVtbl.DragEnter = (PFN_IDropTarget_DragEnter)_glfwDropTarget_DragEnter;
_glfw.win32.dropTargetVtbl.DragOver = (PFN_IDropTarget_DragOver)_glfwDropTarget_DragOver;
_glfw.win32.dropTargetVtbl.DragLeave = (PFN_IDropTarget_DragLeave)_glfwDropTarget_DragLeave;
_glfw.win32.dropTargetVtbl.Drop = (PFN_IDropTarget_Drop)_glfwDropTarget_Drop;
_glfw.win32.dropTargetVtbl.AddRef = _glfwDropTarget_AddRef;
_glfw.win32.dropTargetVtbl.Release = _glfwDropTarget_Release;
_glfw.win32.dropTargetVtbl.DragEnter = _glfwDropTarget_DragEnter;
_glfw.win32.dropTargetVtbl.DragOver = _glfwDropTarget_DragOver;
_glfw.win32.dropTargetVtbl.DragLeave = _glfwDropTarget_DragLeave;
_glfw.win32.dropTargetVtbl.Drop = _glfwDropTarget_Drop;
return GLFW_TRUE;
}

View File

@ -325,12 +325,6 @@ typedef HRESULT (WINAPI * PFN_OleInitialize)(LPVOID);
typedef VOID (WINAPI * PFN_OleUninitialize)(VOID);
typedef HRESULT (WINAPI * PFN_RegisterDragDrop)(HWND,LPDROPTARGET);
typedef HRESULT (WINAPI * PFN_RevokeDragDrop)(HWND);
typedef ULONG (STDMETHODCALLTYPE * PFN_IDropTarget_AddRef)(LPDROPTARGET);
typedef ULONG (STDMETHODCALLTYPE * PFN_IDropTarget_Release)(LPDROPTARGET);
typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragEnter)(LPDROPTARGET,IDataObject*,DWORD,POINTL,DWORD*);
typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragOver)(LPDROPTARGET,DWORD,POINTL,DWORD*);
typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_DragLeave)(LPDROPTARGET);
typedef HRESULT (STDMETHODCALLTYPE * PFN_IDropTarget_Drop)(LPDROPTARGET,IDataObject*,DWORD,POINTL,DWORD*);
#define OleInitialize _glfw.win32.ole32.OleInitialize_
#define OleUninitialize _glfw.win32.ole32.OleUninitialize_
#define RegisterDragDrop _glfw.win32.ole32.RegisterDragDrop_
@ -428,12 +422,17 @@ typedef struct _GLFWlibraryWGL
GLFWbool ARB_context_flush_control;
} _GLFWlibraryWGL;
typedef struct _GLFWdropTarget
typedef struct _GLFWdroptarget
{
IDropTargetVtbl* lpVtbl;
ULONG cRefCount;
_GLFWwindow* window;
} _GLFWdropTarget;
int availableFormats;
int chosenFormat;
int availableActions;
int proposedAction;
int chosenAction;
} _GLFWdroptarget;
// Win32-specific per-window data
//
@ -460,7 +459,7 @@ typedef struct _GLFWwindowWin32
// The last received high surrogate when decoding pairs of UTF-16 messages
WCHAR highSurrogate;
_GLFWdropTarget dropTarget;
_GLFWdroptarget dropTarget;
} _GLFWwindowWin32;
// Win32-specific global data
@ -660,10 +659,10 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWfbconfig* fbconfig);
// IDropTarget vtable functions
//HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This, REFIID riid, void **ppvObject);
ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(_GLFWdropTarget *This);
ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(_GLFWdropTarget *This);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(_GLFWdropTarget *This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(_GLFWdropTarget *This);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
//HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(IDropTarget *_This, REFIID riid, void **ppvObject);
ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(IDropTarget *_This);
ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(IDropTarget *_This);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(IDropTarget *_This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(IDropTarget *_This);
HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);

View File

@ -2472,8 +2472,9 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
}
// IDropTarget vtable functions
HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This, REFIID riid, void **ppvObject)
HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(IDropTarget *_This, REFIID riid, void **ppvObject)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_QueryInterface\n");
if(!ppvObject)
return E_POINTER;
@ -2489,68 +2490,165 @@ HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This,
return E_NOINTERFACE;
}*/
// IDropTarget vtable functions
ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(_GLFWdropTarget *This)
// IDropTarget utility functions
static void getActions(_GLFWdroptarget *This, DWORD dwEffect)
{
This->availableActions = GLFW_DND_NONE;
This->proposedAction = GLFW_DND_NONE;
if ((dwEffect & DROPEFFECT_COPY) == DROPEFFECT_COPY)
{
This->availableActions |= GLFW_DND_COPY;
if (!This->proposedAction)
This->proposedAction = GLFW_DND_COPY;
}
if ((dwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
{
This->availableActions |= GLFW_DND_LINK;
if (!This->proposedAction)
This->proposedAction = GLFW_DND_LINK;
}
if ((dwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
{
This->availableActions |= GLFW_DND_MOVE;
if (!This->proposedAction)
This->proposedAction = GLFW_DND_MOVE;
}
}
static void setActions(_GLFWdroptarget *This, DWORD *pdwEffect)
{
if((This->chosenAction & GLFW_DND_COPY) == GLFW_DND_COPY)
*pdwEffect = DROPEFFECT_COPY;
else if((This->chosenAction & GLFW_DND_LINK) == GLFW_DND_LINK)
*pdwEffect = DROPEFFECT_LINK;
else if((This->chosenAction & GLFW_DND_MOVE) == GLFW_DND_MOVE)
*pdwEffect = DROPEFFECT_MOVE;
else
*pdwEffect = DROPEFFECT_NONE;
}
static FORMATETC *withClipFormat(FORMATETC *pFmt, CLIPFORMAT cf)
{
pFmt->cfFormat = cf;
return pFmt;
}
// IDropTarget vtable functions
ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(IDropTarget *_This)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_AddRef\n");
return ++This->cRefCount;
}
ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(_GLFWdropTarget *This)
ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(IDropTarget *_This)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_Release\n");
return --This->cRefCount;
}
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
FORMATETC fmt = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
FORMATETC fmt = { 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
printf("DropTarget_DragEnter\n");
if(SUCCEEDED(IDataObject_QueryGetData(pDataObj, &fmt)))
getActions(This, *pdwEffect);
This->availableFormats = GLFW_DND_NONE;
if (SUCCEEDED(IDataObject_QueryGetData(pDataObj, withClipFormat(&fmt, CF_HDROP)))
&& SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &stgmed)))
{
printf("QueryGetData OK\n");
*pdwEffect = DROPEFFECT_COPY;
This->availableFormats |= GLFW_DND_PATHS;
printf("paths\n");
}
else
*pdwEffect = DROPEFFECT_NONE;
if (SUCCEEDED(IDataObject_QueryGetData(pDataObj, withClipFormat(&fmt, CF_TEXT)))
&& SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &stgmed)))
{
This->availableFormats |= GLFW_DND_TEXT;
printf("text\n");
ReleaseStgMedium(&stgmed);
}
This->window->dndDragging = GLFW_TRUE;
This->chosenFormat = This->availableFormats;
This->chosenAction = This->proposedAction;
_glfwInputDrag(This->window, GLFW_DND_ENTER, pt.x, pt.y,
This->availableFormats,
&This->chosenFormat,
This->availableActions,
&This->chosenAction);
return S_OK;
}
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(_GLFWdropTarget *This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragOver(IDropTarget *_This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_DragOver\n");
*pdwEffect = DROPEFFECT_COPY;
getActions(This, *pdwEffect);
_glfwInputCursorPos(This->window, pt.x, pt.y);
This->chosenAction = This->proposedAction;
_glfwInputDrag(This->window, GLFW_DND_DRAG, pt.x, pt.y,
This->availableFormats,
&This->chosenFormat,
This->availableActions,
&This->chosenAction);
setActions(This, pdwEffect);
return S_OK;
}
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(_GLFWdropTarget *This)
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(IDropTarget *_This)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_DragLeave\n");
This->window->dndDragging = GLFW_FALSE;
This->chosenFormat =
This->availableFormats = GLFW_DND_NONE;
This->chosenAction =
This->proposedAction =
This->availableActions = GLFW_DND_NONE;
_glfwInputDrag(This->window, GLFW_DND_LEAVE, 0.0, 0.0,
This->availableFormats,
&This->chosenFormat,
This->availableActions,
&This->chosenAction);
return S_OK;
}
HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(_GLFWdropTarget *This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
FORMATETC fmt = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
FORMATETC fmt = { 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
printf("DropTarget_Drop\n");
*pdwEffect = DROPEFFECT_NONE;
if(SUCCEEDED(IDataObject_QueryGetData(pDataObj, &fmt)))
{
printf("QueryGetData OK\n");
if(SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &stgmed)))
This->window->dndDragging = GLFW_FALSE;
if ((This->chosenFormat & GLFW_DND_PATHS) == GLFW_DND_PATHS
&& SUCCEEDED(IDataObject_GetData(pDataObj, withClipFormat(&fmt, CF_HDROP), &stgmed)))
{
HDROP drop = (HDROP) GlobalLock(stgmed.hGlobal);
const int count = DragQueryFileW(drop, 0xffffffff, NULL, 0);
char** paths = _glfw_calloc(count, sizeof(char*));
int i;
printf("GetData OK\n");
printf("GetData OK (paths)\n");
_glfwInputCursorPos(This->window, pt.x, pt.y);
for (i = 0; i < count; ++i)
@ -2566,16 +2664,31 @@ HRESULT STDMETHODCALLTYPE _glfwDropTarget_Drop(_GLFWdropTarget *This, IDataObjec
_glfwInputDrop(This->window, count, (const char**) paths);
_glfwInputDropEx(This->window, GLFW_DND_PATHS, count, paths,
&This->chosenAction);
for (i = 0; i < count; ++i)
_glfw_free(paths[i]);
_glfw_free(paths);
}
else if ((This->chosenFormat & GLFW_DND_TEXT) == GLFW_DND_TEXT
&& SUCCEEDED(IDataObject_GetData(pDataObj, withClipFormat(&fmt, CF_TEXT), &stgmed)))
{
char *text = (char*) GlobalLock(stgmed.hGlobal);
printf("GetData OK (text)\n");
_glfwInputCursorPos(This->window, pt.x, pt.y);
_glfwInputDropEx(This->window, GLFW_DND_TEXT, -1, text,
&This->chosenAction);
}
else
return S_OK;
GlobalUnlock(stgmed.hGlobal);
ReleaseStgMedium(&stgmed);
*pdwEffect = DROPEFFECT_COPY;
}
}
setActions(This, pdwEffect);
return S_OK;
}