Support SDL_EVENT_DROP_FILE in Windows with IDropTarget instead of WM_DROPFILES

Support SDL_EVENT_DROP_TEXT in Windows

  src/video/windows/SDL_windowsvideo.c + .h
    Connect      to COM WIN_CoInitialize   + OLE OleInitialize   in WIN_VideoInit
    Disconnect from COM WIN_CoUninitialize + OLE OleUninitialize in WIN_VideoQuit
  src/video/windows/SDL_windowswindow.c + .h
    Create / Destroy IDropTarget or use fallback WM_DROPFILES
      depending on OleInitialize success in WIN_VideoInit
    Handle text/uri-list, text/plain;charset=utf-8, CF_UNICODE_TEXT, CF_TEXT, CF_HDROP
    Call terminating WIN_AcceptDragAndDrop from WIN_DestroyWindow ( CleanupVideoData )
This commit is contained in:
Dragon-Baroque 2023-09-05 09:15:12 +02:00 committed by Sam Lantinga
parent efefc4a1f3
commit 808c312b2a
4 changed files with 530 additions and 26 deletions

View File

@ -467,6 +467,21 @@ static void WIN_InitDPIAwareness(SDL_VideoDevice *_this)
int WIN_VideoInit(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->internal;
HRESULT hr;
hr = WIN_CoInitialize();
if (SUCCEEDED(hr)) {
data->coinitialized = SDL_TRUE;
hr = OleInitialize(NULL);
if (SUCCEEDED(hr)) {
data->oleinitialized = SDL_TRUE;
} else {
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr);
}
} else {
SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality\n", (unsigned int)hr);
}
WIN_InitDPIAwareness(_this);
@ -511,6 +526,8 @@ int WIN_VideoInit(SDL_VideoDevice *_this)
void WIN_VideoQuit(SDL_VideoDevice *_this)
{
SDL_VideoData *data = _this->internal;
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
WIN_QuitModes(_this);
WIN_QuitDeviceNotification();
@ -525,6 +542,15 @@ void WIN_VideoQuit(SDL_VideoDevice *_this)
WIN_SetRawMouseEnabled(_this, SDL_FALSE);
WIN_SetRawKeyboardEnabled(_this, SDL_FALSE);
if (data->oleinitialized) {
OleUninitialize();
data->oleinitialized = SDL_FALSE;
}
if (data->coinitialized) {
WIN_CoUninitialize();
data->coinitialized = SDL_FALSE;
}
}
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)

View File

@ -379,6 +379,9 @@ struct SDL_VideoData
{
int render;
SDL_bool coinitialized;
SDL_bool oleinitialized;
DWORD clipboard_count;
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) /* Xbox doesn't support user32/shcore*/

View File

@ -24,12 +24,13 @@
#include "../../core/windows/SDL_windows.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../SDL_hints_c.h"
#include "../../events/SDL_dropevents_c.h"
#include "../../events/SDL_keyboard_c.h"
#include "../../events/SDL_mouse_c.h"
#include "../../events/SDL_windowevents_c.h"
#include "../../SDL_hints_c.h"
#include "../SDL_pixels_c.h"
#include "../SDL_sysvideo.h"
#include "SDL_windowsvideo.h"
#include "SDL_windowswindow.h"
@ -188,26 +189,27 @@ static int WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, DWORD
/* Client rect, in points */
switch (rect_type) {
case SDL_WINDOWRECT_CURRENT:
SDL_RelativeToGlobalForWindow(window, window->x, window->y, x, y);
*width = window->w;
*height = window->h;
break;
case SDL_WINDOWRECT_WINDOWED:
SDL_RelativeToGlobalForWindow(window, window->windowed.x, window->windowed.y, x, y);
*width = window->windowed.w;
*height = window->windowed.h;
break;
case SDL_WINDOWRECT_FLOATING:
SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, x, y);
*width = window->floating.w;
*height = window->floating.h;
break;
default:
/* Should never be here */
SDL_assert_release(SDL_FALSE);
*width = 0;
*height = 0;
case SDL_WINDOWRECT_CURRENT:
SDL_RelativeToGlobalForWindow(window, window->x, window->y, x, y);
*width = window->w;
*height = window->h;
break;
case SDL_WINDOWRECT_WINDOWED:
SDL_RelativeToGlobalForWindow(window, window->windowed.x, window->windowed.y, x, y);
*width = window->windowed.w;
*height = window->windowed.h;
break;
case SDL_WINDOWRECT_FLOATING:
SDL_RelativeToGlobalForWindow(window, window->floating.x, window->floating.y, x, y);
*width = window->floating.w;
*height = window->floating.h;
break;
default:
/* Should never be here */
SDL_assert_release(SDL_FALSE);
*width = 0;
*height = 0;
break;
}
/* Copy the client size in pixels into this rect structure,
@ -587,6 +589,10 @@ static void CleanupWindowData(SDL_VideoDevice *_this, SDL_Window *window)
if (data) {
SDL_DelHintCallback(SDL_HINT_MOUSE_RELATIVE_MODE_CENTER, WIN_MouseRelativeModeCenterChanged, data);
if (data->drop_target) {
WIN_AcceptDragAndDrop(window, SDL_FALSE);
}
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
if (data->ICMFileName) {
SDL_free(data->ICMFileName);
@ -1136,7 +1142,7 @@ void WIN_MaximizeWindow(SDL_VideoDevice *_this, SDL_Window *window)
SetWindowPos(hwnd, HWND_TOP, fx, fy, fw, fh, data->copybits_flag | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOACTIVATE);
data->expected_resize = SDL_FALSE;
}
}else {
} else {
data->windowed_mode_was_maximized = SDL_TRUE;
}
}
@ -1693,10 +1699,468 @@ int WIN_SetWindowOpacity(SDL_VideoDevice *_this, SDL_Window *window, float opaci
}
#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
static const char *SDLGetClipboardFormatName(UINT cf, char *text, int len)
{
switch (cf) {
case CF_TEXT:
return "CF_TEXT";
case CF_BITMAP:
return "CF_BITMAP";
case CF_METAFILEPICT:
return "CF_METAFILEPICT";
case CF_SYLK:
return "CF_SYLK";
case CF_DIF:
return "CF_DIF";
case CF_TIFF:
return "CF_TIFF";
case CF_OEMTEXT:
return "CF_OEMTEXT";
case CF_DIB:
return "CF_DIB";
case CF_PALETTE:
return "CF_PALETTE";
case CF_PENDATA:
return "CF_PENDATA";
case CF_RIFF:
return "CF_RIFF";
case CF_WAVE:
return "CF_WAVE";
case CF_UNICODETEXT:
return "CF_UNICODETEXT";
case CF_ENHMETAFILE:
return "CF_ENHMETAFILE";
case CF_HDROP:
return "CF_HDROP";
case CF_LOCALE:
return "CF_LOCALE";
case CF_DIBV5:
return "CF_DIBV5";
case CF_OWNERDISPLAY:
return "CF_OWNERDISPLAY";
case CF_DSPTEXT:
return "CF_DSPTEXT";
case CF_DSPBITMAP:
return "CF_DSPBITMAP";
case CF_DSPMETAFILEPICT:
return "CF_DSPMETAFILEPICT";
case CF_DSPENHMETAFILE:
return "CF_DSPENHMETAFILE";
default:
if (GetClipboardFormatNameA(cf, text, len)) {
return text;
} else {
return NULL;
}
}
}
static STDMETHODIMP_(ULONG) SDLDropTarget_AddRef(SDLDropTarget *target)
{
return ++target->refcount;
}
static STDMETHODIMP_(ULONG) SDLDropTarget_Release(SDLDropTarget *target)
{
--target->refcount;
if (target->refcount == 0) {
SDL_free(target);
return 0;
}
return target->refcount;
}
static STDMETHODIMP SDLDropTarget_QueryInterface(SDLDropTarget *target, REFIID riid, PVOID *ppv)
{
if (ppv == NULL) {
return E_INVALIDARG;
}
*ppv = NULL;
if (WIN_IsEqualIID(riid, &IID_IUnknown) ||
WIN_IsEqualIID(riid, &IID_IDropTarget)) {
*ppv = (void *)target;
}
if (*ppv) {
SDLDropTarget_AddRef(target);
return S_OK;
}
return E_NOINTERFACE;
}
static STDMETHODIMP SDLDropTarget_DragEnter(SDLDropTarget *target,
IDataObject *pDataObject, DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragEnter at %ld, %ld\n", pt.x, pt.y);
*pdwEffect = DROPEFFECT_COPY;
POINT pnt = { pt.x, pt.y };
if (ScreenToClient(target->hwnd, &pnt)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragEnter at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragEnter at %ld, %ld => nil, nil\n", pt.x, pt.y);
}
return S_OK;
}
static STDMETHODIMP SDLDropTarget_DragOver(SDLDropTarget *target,
DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragOver at %ld, %ld\n", pt.x, pt.y);
*pdwEffect = DROPEFFECT_COPY;
POINT pnt = { pt.x, pt.y };
if (ScreenToClient(target->hwnd, &pnt)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragOver at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragOver at %ld, %ld => nil, nil\n", pt.x, pt.y);
}
return S_OK;
}
static STDMETHODIMP SDLDropTarget_DragLeave(SDLDropTarget *target)
{
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In DragLeave\n");
SDL_SendDropComplete(target->window);
return S_OK;
}
static STDMETHODIMP SDLDropTarget_Drop(SDLDropTarget *target,
IDataObject *pDataObject, DWORD grfKeyState,
POINTL pt, DWORD *pdwEffect)
{
*pdwEffect = DROPEFFECT_COPY;
POINT pnt = { pt.x, pt.y };
if (ScreenToClient(target->hwnd, &pnt)) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop at %ld, %ld => window %u at %ld, %ld\n", pt.x, pt.y, target->window->id, pnt.x, pnt.y);
SDL_SendDropPosition(target->window, pnt.x, pnt.y);
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop at %ld, %ld => nil, nil\n", pt.x, pt.y);
}
{
IEnumFORMATETC *pEnumFormatEtc;
HRESULT hres;
hres = pDataObject->lpVtbl->EnumFormatEtc(pDataObject, DATADIR_GET, &pEnumFormatEtc);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop for EnumFormatEtc, HRESULT is %08lx\n", hres);
if (hres == S_OK) {
FORMATETC fetc;
while (pEnumFormatEtc->lpVtbl->Next(pEnumFormatEtc, 1, &fetc, NULL) == S_OK) {
char name[257] = { 0 };
const char *cfnm = SDLGetClipboardFormatName(fetc.cfFormat, name, 256);
if (cfnm) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop, Supported format is %08x, '%s'\n", fetc.cfFormat, cfnm);
} else {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop, Supported format is %08x, Predefined\n", fetc.cfFormat);
}
}
}
}
{
FORMATETC fetc;
fetc.cfFormat = target->format_file;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
const char *format_mime = "text/uri-list";
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for QueryGetData, format %08x '%s', success\n",
fetc.cfFormat, format_mime);
STGMEDIUM med;
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n",
fetc.cfFormat, format_mime, hres);
if (SUCCEEDED(hres)) {
const size_t bsize = GlobalSize(med.hGlobal);
const void *buffer = (void *)GlobalLock(med.hGlobal);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
if (buffer) {
char *text = SDL_malloc(bsize + sizeof(Uint32));
SDL_memcpy((Uint8 *)text, buffer, bsize);
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
char *saveptr = NULL;
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
while (token != NULL) {
if (SDL_URIToLocal(token, token) >= 0) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File, file (%lu of %lu) '%s'\n",
(unsigned long)strlen(token), (unsigned long)bsize, token);
SDL_SendDropFile(target->window, NULL, token);
}
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
}
SDL_free(text);
}
GlobalUnlock(med.hGlobal);
ReleaseStgMedium(&med);
SDL_SendDropComplete(target->window);
return S_OK;
}
}
}
{
FORMATETC fetc;
fetc.cfFormat = target->format_text;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
const char *format_mime = "text/plain;charset=utf-8";
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for QueryGetData, format %08x '%s', success\n",
fetc.cfFormat, format_mime);
STGMEDIUM med;
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
fetc.cfFormat, format_mime, hres);
if (SUCCEEDED(hres)) {
const size_t bsize = GlobalSize(med.hGlobal);
const void *buffer = (void *)GlobalLock(med.hGlobal);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
if (buffer) {
char *text = SDL_malloc(bsize + sizeof(Uint32));
SDL_memcpy((Uint8 *)text, buffer, bsize);
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
char *saveptr = NULL;
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
while (token != NULL) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text, text (%lu of %lu) '%s'\n",
(unsigned long)strlen(token), (unsigned long)bsize, token);
SDL_SendDropText(target->window, (char *)token);
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
}
SDL_free(text);
}
GlobalUnlock(med.hGlobal);
ReleaseStgMedium(&med);
SDL_SendDropComplete(target->window);
return S_OK;
}
}
}
{
FORMATETC fetc;
fetc.cfFormat = CF_UNICODETEXT;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
const char *format_mime = "CF_UNICODETEXT";
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for QueryGetData, format %08x '%s', success\n",
fetc.cfFormat, format_mime);
STGMEDIUM med;
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
fetc.cfFormat, format_mime, hres);
if (SUCCEEDED(hres)) {
const size_t bsize = GlobalSize(med.hGlobal);
const void *buffer = (void *)GlobalLock(med.hGlobal);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
if (buffer) {
buffer = WIN_StringToUTF8(buffer);
if (buffer) {
const size_t lbuffer = strlen(buffer);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for StringToUTF8, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)lbuffer, buffer);
char *text = SDL_malloc(lbuffer + sizeof(Uint32));
SDL_memcpy((Uint8 *)text, buffer, lbuffer);
SDL_memset((Uint8 *)text + lbuffer, 0, sizeof(Uint32));
char *saveptr = NULL;
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
while (token != NULL) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text, text (%lu of %lu) '%s'\n",
(unsigned long)strlen(token), (unsigned long)lbuffer, token);
SDL_SendDropText(target->window, (char *)token);
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
}
SDL_free(text);
SDL_free((void *)buffer);
}
}
GlobalUnlock(med.hGlobal);
ReleaseStgMedium(&med);
SDL_SendDropComplete(target->window);
return S_OK;
}
}
}
{
FORMATETC fetc;
fetc.cfFormat = CF_TEXT;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
const char *format_mime = "CF_TEXT";
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for QueryGetData, format %08x '%s', success\n",
fetc.cfFormat, format_mime);
STGMEDIUM med;
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GetData, format %08x '%s', HRESULT is %08lx\n",
fetc.cfFormat, format_mime, hres);
if (SUCCEEDED(hres)) {
const size_t bsize = GlobalSize(med.hGlobal);
const void *buffer = (void *)GlobalLock(med.hGlobal);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text for GlobalLock, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)bsize, buffer);
if (buffer) {
char *text = SDL_malloc(bsize + sizeof(Uint32));
SDL_memcpy((Uint8 *)text, buffer, bsize);
SDL_memset((Uint8 *)text + bsize, 0, sizeof(Uint32));
char *saveptr = NULL;
char *token = SDL_strtok_r(text, "\r\n", &saveptr);
while (token != NULL) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop Text, text (%lu of %lu) '%s'\n",
(unsigned long)strlen(token), (unsigned long)bsize, token);
SDL_SendDropText(target->window, (char *)token);
token = SDL_strtok_r(NULL, "\r\n", &saveptr);
}
SDL_free(text);
}
GlobalUnlock(med.hGlobal);
ReleaseStgMedium(&med);
SDL_SendDropComplete(target->window);
return S_OK;
}
}
}
{
FORMATETC fetc;
fetc.cfFormat = CF_HDROP;
fetc.ptd = NULL;
fetc.dwAspect = DVASPECT_CONTENT;
fetc.lindex = -1;
fetc.tymed = TYMED_HGLOBAL;
const char *format_mime = "CF_HDROP";
if (SUCCEEDED(pDataObject->lpVtbl->QueryGetData(pDataObject, &fetc))) {
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for QueryGetData, format %08x '%s', success\n",
fetc.cfFormat, format_mime);
STGMEDIUM med;
HRESULT hres = pDataObject->lpVtbl->GetData(pDataObject, &fetc, &med);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for GetData, format %08x '%s', HRESULT is %08lx\n",
fetc.cfFormat, format_mime, hres);
if (SUCCEEDED(hres)) {
const size_t bsize = GlobalSize(med.hGlobal);
HDROP drop = (HDROP)GlobalLock(med.hGlobal);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File for GlobalLock, format %08x '%s', memory (%lu) %p\n",
fetc.cfFormat, format_mime, (unsigned long)bsize, drop);
UINT count = DragQueryFile(drop, 0xFFFFFFFF, NULL, 0);
for (UINT i = 0; i < count; ++i) {
SDL_bool isstack;
UINT size = DragQueryFile(drop, i, NULL, 0) + 1;
LPTSTR buffer = SDL_small_alloc(TCHAR, size, &isstack);
if (buffer) {
if (DragQueryFile(drop, i, buffer, size)) {
char *file = WIN_StringToUTF8(buffer);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Drop File, file (%lu of %lu) '%s'\n",
(unsigned long)strlen(file), (unsigned long)bsize, file);
SDL_SendDropFile(target->window, NULL, file);
SDL_free(file);
}
SDL_small_free(buffer, isstack);
}
}
GlobalUnlock(med.hGlobal);
ReleaseStgMedium(&med);
SDL_SendDropComplete(target->window);
return S_OK;
}
}
}
SDL_SendDropComplete(target->window);
return S_OK;
}
static void *vtDropTarget[] = {
(void *)(SDLDropTarget_QueryInterface),
(void *)(SDLDropTarget_AddRef),
(void *)(SDLDropTarget_Release),
(void *)(SDLDropTarget_DragEnter),
(void *)(SDLDropTarget_DragOver),
(void *)(SDLDropTarget_DragLeave),
(void *)(SDLDropTarget_Drop)
};
void WIN_AcceptDragAndDrop(SDL_Window *window, SDL_bool accept)
{
const SDL_WindowData *data = window->internal;
DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
SDL_WindowData *data = window->internal;
if (data->videodata->oleinitialized) {
if (accept && !data->drop_target) {
SDLDropTarget *drop_target = (SDLDropTarget *)SDL_calloc(1, sizeof(SDLDropTarget));
if (drop_target != NULL) {
drop_target->lpVtbl = vtDropTarget;
drop_target->window = window;
drop_target->hwnd = data->hwnd;
drop_target->format_file = RegisterClipboardFormat(L"text/uri-list");
drop_target->format_text = RegisterClipboardFormat(L"text/plain;charset=utf-8");
data->drop_target = drop_target;
SDLDropTarget_AddRef(drop_target);
RegisterDragDrop(data->hwnd, (LPDROPTARGET)drop_target);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Accept Drag and Drop, window %u, enabled Full OLE IDropTarget\n",
window->id);
}
} else if (!accept && data->drop_target) {
RevokeDragDrop(data->hwnd);
SDLDropTarget_Release(data->drop_target);
data->drop_target = NULL;
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Accept Drag and Drop, window %u, disabled Full OLE IDropTarget\n",
window->id);
}
} else {
DragAcceptFiles(data->hwnd, accept ? TRUE : FALSE);
SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
". In Accept Drag and Drop, window %u, %s Fallback WM_DROPFILES\n",
window->id, (accept ? "enabled" : "disabled"));
}
}
int WIN_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation)

View File

@ -48,6 +48,16 @@ typedef enum SDL_WindowEraseBackgroundMode
SDL_ERASEBACKGROUNDMODE_ALWAYS,
} SDL_WindowEraseBackgroundMode;
typedef struct
{
void **lpVtbl;
int refcount;
SDL_Window *window;
HWND hwnd;
UINT format_text;
UINT format_file;
} SDLDropTarget;
struct SDL_WindowData
{
SDL_Window *window;
@ -89,6 +99,7 @@ struct SDL_WindowData
/* Whether we retain the content of the window when changing state */
UINT copybits_flag;
SDLDropTarget *drop_target;
};
extern int WIN_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_PropertiesID create_props);