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.QueryInterface = _glfwDropTarget_QueryInterface;
_glfw.win32.dropTargetVtbl.AddRef = (PFN_IDropTarget_AddRef)_glfwDropTarget_AddRef; _glfw.win32.dropTargetVtbl.AddRef = _glfwDropTarget_AddRef;
_glfw.win32.dropTargetVtbl.Release = (PFN_IDropTarget_Release)_glfwDropTarget_Release; _glfw.win32.dropTargetVtbl.Release = _glfwDropTarget_Release;
_glfw.win32.dropTargetVtbl.DragEnter = (PFN_IDropTarget_DragEnter)_glfwDropTarget_DragEnter; _glfw.win32.dropTargetVtbl.DragEnter = _glfwDropTarget_DragEnter;
_glfw.win32.dropTargetVtbl.DragOver = (PFN_IDropTarget_DragOver)_glfwDropTarget_DragOver; _glfw.win32.dropTargetVtbl.DragOver = _glfwDropTarget_DragOver;
_glfw.win32.dropTargetVtbl.DragLeave = (PFN_IDropTarget_DragLeave)_glfwDropTarget_DragLeave; _glfw.win32.dropTargetVtbl.DragLeave = _glfwDropTarget_DragLeave;
_glfw.win32.dropTargetVtbl.Drop = (PFN_IDropTarget_Drop)_glfwDropTarget_Drop; _glfw.win32.dropTargetVtbl.Drop = _glfwDropTarget_Drop;
return GLFW_TRUE; return GLFW_TRUE;
} }

View File

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

View File

@ -2472,8 +2472,9 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
} }
// IDropTarget vtable functions // 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"); printf("DropTarget_QueryInterface\n");
if(!ppvObject) if(!ppvObject)
return E_POINTER; return E_POINTER;
@ -2489,93 +2490,205 @@ HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(_GLFWdropTarget *This,
return E_NOINTERFACE; return E_NOINTERFACE;
}*/ }*/
// IDropTarget vtable functions // IDropTarget utility functions
ULONG STDMETHODCALLTYPE _glfwDropTarget_AddRef(_GLFWdropTarget *This) 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"); printf("DropTarget_AddRef\n");
return ++This->cRefCount; return ++This->cRefCount;
} }
ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(_GLFWdropTarget *This) ULONG STDMETHODCALLTYPE _glfwDropTarget_Release(IDropTarget *_This)
{ {
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_Release\n"); printf("DropTarget_Release\n");
return --This->cRefCount; 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"); 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"); This->availableFormats |= GLFW_DND_PATHS;
*pdwEffect = DROPEFFECT_COPY; printf("paths\n");
} }
else if (SUCCEEDED(IDataObject_QueryGetData(pDataObj, withClipFormat(&fmt, CF_TEXT)))
*pdwEffect = DROPEFFECT_NONE; && 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; 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"); 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; return S_OK;
} }
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(_GLFWdropTarget *This) HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragLeave(IDropTarget *_This)
{ {
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_DragLeave\n"); 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; 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; STGMEDIUM stgmed;
printf("DropTarget_Drop\n"); printf("DropTarget_Drop\n");
*pdwEffect = DROPEFFECT_NONE; *pdwEffect = DROPEFFECT_NONE;
if(SUCCEEDED(IDataObject_QueryGetData(pDataObj, &fmt))) This->window->dndDragging = GLFW_FALSE;
{
printf("QueryGetData OK\n");
if(SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &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"); if ((This->chosenFormat & GLFW_DND_PATHS) == GLFW_DND_PATHS
_glfwInputCursorPos(This->window, pt.x, pt.y); && 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;
for (i = 0; i < count; ++i) printf("GetData OK (paths)\n");
{ _glfwInputCursorPos(This->window, pt.x, pt.y);
const UINT length = DragQueryFileW(drop, i, NULL, 0);
WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR));
DragQueryFileW(drop, i, buffer, length + 1); for (i = 0; i < count; ++i)
paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer); {
const UINT length = DragQueryFileW(drop, i, NULL, 0);
WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR));
_glfw_free(buffer); DragQueryFileW(drop, i, buffer, length + 1);
} paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
_glfwInputDrop(This->window, count, (const char**) paths); _glfw_free(buffer);
}
for (i = 0; i < count; ++i) _glfwInputDrop(This->window, count, (const char**) paths);
_glfw_free(paths[i]);
_glfw_free(paths);
GlobalUnlock(stgmed.hGlobal); _glfwInputDropEx(This->window, GLFW_DND_PATHS, count, paths,
ReleaseStgMedium(&stgmed); &This->chosenAction);
*pdwEffect = DROPEFFECT_COPY; 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);
setActions(This, pdwEffect);
return S_OK; return S_OK;
} }