diff --git a/include/Mw/LowLevel/GDI.h b/include/Mw/LowLevel/GDI.h index 5cc5f09..6230a36 100644 --- a/include/Mw/LowLevel/GDI.h +++ b/include/Mw/LowLevel/GDI.h @@ -31,26 +31,9 @@ struct _MwLLGDI { int get_darktheme; /* drag and drop */ - void *shell32lib; - void *ole32lib; - void *urlmonlib; - UINT (*DragQueryFileW)(HDROP hDrop,UINT iFile,LPWSTR lpszFile,UINT cch); - void (*ReleaseStgMedium)(LPSTGMEDIUM unnamedParam1); - HRESULT (*OleInitialize)(LPVOID pvReserved); - HRESULT (*RegisterDragDrop)(HWND hwnd, LPDROPTARGET pDropTarget); - HRESULT (*FindMimeFromData)( - LPBC pBC, - LPCWSTR pwzUrl, - LPVOID pBuffer, - DWORD cbSize, - LPCWSTR pwzMimeProposed, - DWORD dwMimeFlags, - LPWSTR *ppwzMimeOut, - _Reserved_ DWORD dwReserved - ); struct _MwLLGDIDropTarget* dropTarget; - MwBool listening_for_drag_and_drop; - MwBool dnd_override; + struct _MwLLGDIDropSource* dropSource; + MwBool drag_update; }; struct _MwLLGDIColor { diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 01f69a5..5f9e3e4 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -101,5 +101,6 @@ #define MwNdrawHandler "Cdraw" #define MwNclipboardHandler "Cclipboard" #define MwNdarkThemeHandler "CdarkTheme" +#define MwNdragAndDropHandler "CdragAndDrop" #endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 5989e1b..fbc91fa 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -274,7 +274,7 @@ struct _MwClass { MwHandlerChildrenProp children_prop_change; MwHandlerClipboardReceived clipboard; MwHandlerProps props_change; - void* reserved1; + MwHandler drag_and_drop; void* reserved2; void* reserved3; }; diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 0f2c550..a005a74 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -12,8 +12,27 @@ typedef struct userdata { static struct symtbl { void* lib_dwmapi; + void *shell32lib; + void *ole32lib; + void *urlmonlib; + MwBool has_drag_and_drop; HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + UINT (WINAPI *DragQueryFileW)(HDROP hDrop,UINT iFile,LPWSTR lpszFile,UINT cch); + UINT (WINAPI *DragQueryFileA)(HDROP hDrop,UINT iFile,LPSTR lpszFile,UINT cch); + void (WINAPI *ReleaseStgMedium)(LPSTGMEDIUM unnamedParam1); + HRESULT (WINAPI *OleInitialize)(LPVOID pvReserved); + HRESULT (WINAPI *RegisterDragDrop)(HWND hwnd, LPDROPTARGET pDropTarget); + HRESULT (WINAPI *FindMimeFromData)( + LPBC pBC, + LPCWSTR pwzUrl, + LPVOID pBuffer, + DWORD cbSize, + LPCWSTR pwzMimeProposed, + DWORD dwMimeFlags, + LPWSTR *ppwzMimeOut, + _Reserved_ DWORD dwReserved + ); } wsymtbl; static int is_plgblt_reliable = 0; @@ -422,6 +441,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { SetWindowPos(r->gdi.hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + r->gdi.dropTarget = NULL; + r->gdi.drag_update = MwFALSE; + return r; } @@ -436,6 +458,8 @@ static void MwLLDestroyImpl(MwLL handle) { if(handle->gdi.cursor != NULL) DestroyCursor(handle->gdi.cursor); + if(handle->gdi.dropTarget) free(handle->gdi.dropTarget); + free(handle); } @@ -549,8 +573,7 @@ static int MwLLPendingImpl(MwLL handle) { (void)handle; - - if(handle->gdi.get_clipboard || handle->gdi.get_darktheme) return 1; + if(handle->gdi.get_clipboard || handle->gdi.get_darktheme || handle->gdi.drag_update) return 1; return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0; } @@ -582,8 +605,7 @@ static void MwLLNextEventImpl(MwLL handle) { handle->gdi.get_darktheme = 0; } - while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { - GetMessage(&msg, handle->gdi.hWnd, 0, 0); + while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } @@ -1021,46 +1043,21 @@ static ULONG STDMETHODCALLTYPE GDIDT_Release(IDropTarget* this_) { static HRESULT STDMETHODCALLTYPE GDIDT_DragEnter(IDropTarget* this_, IDataObject* pDataObj, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { - FORMATETC fmt = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; - STGMEDIUM stg; - MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; - - if(pDataObj->lpVtbl->GetData(pDataObj, &fmt, &stg) == S_OK) { - HDROP hDrop = (HDROP)stg.hGlobal; - UINT count = self->handle->gdi.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); - UINT i; - HRESULT hr; - - for(i = 0; i < count; i++) { - wchar_t path[MAX_PATH]; - char mime_type_normal[MAX_PATH]; - wchar_t *mime_type = NULL; - HRESULT hr; - int i; - self->handle->gdi.DragQueryFileW(hDrop, i, path, MAX_PATH); - hr = self->handle->gdi.FindMimeFromData( NULL, path, NULL, 0, - NULL, FMFD_URLASFILENAME, &mime_type, 0x0 ); - - wprintf(L"Dragged: %s\n", mime_type); - /* TODO: Check if the file begin dragged matches a mime type registered with MwNacceptedMimeType, and only set the effect to DROPEFFECT_COPY if so */ - *pdwEffect = DROPEFFECT_COPY; - break; - } - - self->handle->gdi.ReleaseStgMedium(&stg); - } else { - *pdwEffect = DROPEFFECT_NONE; - } - + *pdwEffect = DROPEFFECT_COPY; return S_OK; } static HRESULT STDMETHODCALLTYPE GDIDT_DragOver(IDropTarget* this_, DWORD grfKeyState, POINTL pt, DWORD* pdwEffect) { + MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; + self->handle->gdi.drag_update = MwTRUE; + return S_OK; } static HRESULT STDMETHODCALLTYPE GDIDT_DragLeave(IDropTarget* this_) { + MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; + self->handle->gdi.drag_update = MwFALSE; return S_OK; } @@ -1070,27 +1067,50 @@ static HRESULT STDMETHODCALLTYPE GDIDT_Drop(IDropTarget* this_, IDataObject* pDa STGMEDIUM stg; MwLLGDIDropTarget* self = (MwLLGDIDropTarget*)this_; + self->handle->gdi.drag_update = MwTRUE; + if(pDataObj->lpVtbl->GetData(pDataObj, &fmt, &stg) == S_OK) { HDROP hDrop = (HDROP)stg.hGlobal; - UINT count = self->handle->gdi.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); - UINT i; + UINT count = wsymtbl.DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0); + UINT i, n; HRESULT hr; for(i = 0; i < count; i++) { wchar_t path[MAX_PATH]; - char mime_type_normal[MAX_PATH]; + char path_normal[MAX_PATH]; + char *mime_type_normal; wchar_t *mime_type = NULL; + int mime_type_size; HRESULT hr; int i; - self->handle->gdi.DragQueryFileW(hDrop, i, path, MAX_PATH); - hr = self->handle->gdi.FindMimeFromData( NULL, path, NULL, 0, - NULL, FMFD_URLASFILENAME, &mime_type, 0x0 ); - /* TODO: Check if the file begin dragged matches a mime type registered with MwNacceptedMimeType, and call a user callback */ - wprintf(L"Dropped: %s\n", mime_type); + wsymtbl.DragQueryFileW(hDrop, i, path, MAX_PATH); + wsymtbl.DragQueryFileA(hDrop, i, path_normal, MAX_PATH); + hr = wsymtbl.FindMimeFromData( NULL, path, NULL, 0, + NULL, FMFD_DEFAULT , &mime_type, 0x0 ); + + mime_type_size = WideCharToMultiByte(CP_ACP, 0, mime_type, -1, NULL, 0, NULL, FALSE); + mime_type_normal = malloc(sizeof(mime_type_size)); + WideCharToMultiByte(CP_ACP, 0, mime_type, -1, mime_type_normal, mime_type_size, NULL, FALSE); + + if(mime_type_size == 0) { + printf("Error converting mime type to multi-byte: %ld\n",GetLastError()); + } else { + if(self->handle->common.known_mime_types) { + for(n = 0; n < arrlen(self->handle->common.known_mime_types); n++) { + if(strcmp(mime_type_normal, self->handle->common.known_mime_types[n]) == 0) { + MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); + break; + } + } + } else { + MwDispatchUserHandler(self->handle->common.user, MwNdragAndDropHandler, path_normal); + } + } + free(mime_type); } - self->handle->gdi.ReleaseStgMedium(&stg); + wsymtbl.ReleaseStgMedium(&stg); *pdwEffect = DROPEFFECT_COPY; } else { *pdwEffect = DROPEFFECT_NONE; @@ -1098,6 +1118,7 @@ static HRESULT STDMETHODCALLTYPE GDIDT_Drop(IDropTarget* this_, IDataObject* pDa return S_OK; } + static IDropTargetVtbl DropTarget_Vtbl = { GDIDT_QueryInterface, GDIDT_AddRef, @@ -1108,20 +1129,25 @@ static IDropTargetVtbl DropTarget_Vtbl = { GDIDT_Drop}; static void MwLLSetupDragAndDropImpl(MwLL handle) { - HRESULT hr = 0; + HRESULT hr = 0; - if(!(handle->gdi.shell32lib = LoadLibrary("shell32.dll"))) return; - if(!(handle->gdi.ole32lib = LoadLibrary("ole32.dll"))) return; - if(!(handle->gdi.urlmonlib = LoadLibrary("Urlmon.dll"))) return; + handle->gdi.dropTarget = (MwLLGDIDropTarget*)malloc(sizeof(MwLLGDIDropTarget)); + handle->gdi.dropTarget->lpVtbl = &DropTarget_Vtbl; + handle->gdi.dropTarget->refCount = 1; + handle->gdi.dropTarget->hwnd = handle->gdi.hWnd; + handle->gdi.dropTarget->handle = handle; -#define SHELL32_FUNC(x) if(!(handle->gdi.x = (void*)GetProcAddress(handle->gdi.shell32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); return;} -#define OLE32_FUNC(x) if(!(handle->gdi.x = (void*)GetProcAddress(handle->gdi.ole32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); return;} -#define URLMON_FUNC(x) if(!(handle->gdi.x = (void*)GetProcAddress(handle->gdi.urlmonlib, #x))) {printf(#x "not found, drag and drop will not be supported"); return;} + hr = wsymtbl.RegisterDragDrop(handle->gdi.hWnd, (IDropTarget*)handle->gdi.dropTarget); + if(!SUCCEEDED(hr)) { + printf("RegisterDragDrop failed; %08lx\n", hr); + return; + } + printf("dnd setup\n"); +} - SHELL32_FUNC(DragQueryFileW); - OLE32_FUNC(ReleaseStgMedium); - OLE32_FUNC(RegisterDragDrop); - URLMON_FUNC(FindMimeFromData); +static int MwLLGDICallInitImpl(void) { + void* ntdll; + HRESULT hr; CoInitialize(NULL); hr = OleInitialize(NULL); @@ -1132,27 +1158,10 @@ static void MwLLSetupDragAndDropImpl(MwLL handle) { CoInitialize(NULL); } else { printf("OleInitialize failed; %08lx\n", hr); - return; + return 1; } } - handle->gdi.dropTarget = (MwLLGDIDropTarget*)malloc(sizeof(MwLLGDIDropTarget)); - handle->gdi.dropTarget->lpVtbl = &DropTarget_Vtbl; - handle->gdi.dropTarget->refCount = 1; - handle->gdi.dropTarget->hwnd = handle->gdi.hWnd; - handle->gdi.dropTarget->handle = handle; - - hr = handle->gdi.RegisterDragDrop(handle->gdi.hWnd, (IDropTarget*)handle->gdi.dropTarget); - if(!SUCCEEDED(hr)) { - printf("RegisterDragDrop failed; %08lx\n", hr); - return; - } - printf("dnd setup\n"); -} - -static int MwLLGDICallInitImpl(void) { - void* ntdll; - memset(&wsymtbl, 0, sizeof(wsymtbl)); wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); @@ -1165,6 +1174,24 @@ static int MwLLGDICallInitImpl(void) { is_plgblt_reliable = 1; } + wsymtbl.has_drag_and_drop = MwTRUE; + + if(!(wsymtbl.shell32lib = LoadLibrary("shell32.dll"))) {goto dnd_error;}; + if(!(wsymtbl.ole32lib = LoadLibrary("ole32.dll"))) {goto dnd_error;}; + if(!(wsymtbl.urlmonlib = LoadLibrary("Urlmon.dll"))) {goto dnd_error;}; + +#define SHELL32_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.shell32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} +#define OLE32_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.ole32lib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} +#define URLMON_FUNC(x) if(!(wsymtbl.x = (void*)GetProcAddress(wsymtbl.urlmonlib, #x))) {printf(#x "not found, drag and drop will not be supported"); goto dnd_error;} + + SHELL32_FUNC(DragQueryFileW); + SHELL32_FUNC(DragQueryFileA); + OLE32_FUNC(ReleaseStgMedium); + OLE32_FUNC(RegisterDragDrop); + URLMON_FUNC(FindMimeFromData); + + wsymtbl.has_drag_and_drop = MwTRUE; +dnd_error: /* TODO: check properly */ return 0; } diff --git a/src/lowlevel.c b/src/lowlevel.c index 38a1ab0..aca10c2 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -64,6 +64,7 @@ void MwLLCreateCommon(MwLL handle) { memset(handle->common.handler, 0, sizeof(*handle->common.handler)); handle->common.supports_transparency = 0; + handle->common.known_mime_types = NULL; } void MwLLDestroyCommon(MwLL handle) {