This commit is contained in:
Florian Albrechtskirchinger 2022-07-27 09:10:26 +09:00 committed by GitHub
commit 0ad98d3f74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 704 additions and 29 deletions

View File

@ -80,8 +80,89 @@ static void key_callback(GLFWwindow* window, int key, int scancode, int action,
glfwSetWindowShouldClose(window, GLFW_TRUE);
}
void drag_callback(GLFWwindow* window, int event, double xpos, double ypos, int availableFormats, int *format, int availableActions, int *action)
{
int width, height;
glfwGetWindowSize(window, &width, &height);
switch(event)
{
case GLFW_DND_ENTER:
{
printf("ENTER (%d, %d)\n", (int)xpos, (int)ypos);
break;
}
case GLFW_DND_DRAG:
{
printf("DRAG (%d, %d)\n", (int)xpos, (int)ypos);
if ((int) xpos < (width / 2))
{
if ((availableFormats & GLFW_DND_PATHS) == GLFW_DND_PATHS)
{
printf("accepting paths\n");
*format = GLFW_DND_PATHS;
}
else
{
printf("reject\n");
*action = GLFW_DND_NONE;
}
}
else {
if ((availableFormats & GLFW_DND_TEXT) == GLFW_DND_TEXT)
{
printf("accepting text\n");
*format = GLFW_DND_TEXT;
}
else
{
printf("reject\n");
*action = GLFW_DND_NONE;
}
}
break;
}
case GLFW_DND_LEAVE:
{
printf("LEAVE\n");
break;
}
}
}
void drop_callback(GLFWwindow* window, int count, const char** paths)
{
for (int i = 0; i < count; ++i)
printf("path[%d]: %s\n", i, paths[i]);
}
void dropex_callback(GLFWwindow* window, int format, int data_count, void *data, int *action)
{
printf("DROP\n");
switch(format)
{
case GLFW_DND_PATHS:
{
const char **paths = (const char **) data;
for(int i = 0; i < data_count; ++i)
printf("path[%d]: %s\n", i, paths[i]);
break;
}
case GLFW_DND_TEXT:
printf("text: %s\n", (const char *) data);
break;
default:
break;
}
}
int main(void)
{
(void)setvbuf(stdout, NULL, _IONBF, 0);
(void)setvbuf(stderr, NULL, _IONBF, 0);
glfwSetErrorCallback(error_callback);
if (!glfwInit())
@ -99,6 +180,9 @@ int main(void)
}
glfwSetKeyCallback(window, key_callback);
glfwSetDragCallback(window, drag_callback);
glfwSetDropCallback(window, drop_callback);
glfwSetDropCallbackEx(window, dropex_callback);
glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress);
@ -149,7 +233,8 @@ int main(void)
mat4x4 m, p, mvp;
mat4x4_identity(m);
mat4x4_rotate_Z(m, m, (float) glfwGetTime());
if (glfwGetWindowAttrib(window, GLFW_DND_DRAGGING))
mat4x4_rotate_Z(m, m, (float) glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m);

View File

@ -927,6 +927,9 @@ extern "C" {
*/
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D
// TODO doc
#define GLFW_DND_DRAGGING 0x0002000E
/*! @brief Framebuffer bit depth hint.
*
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -1309,6 +1312,25 @@ extern "C" {
#define GLFW_PLATFORM_NULL 0x00060005
/*! @} */
// TODO doc
#define GLFW_DND_NONE 0
// Drag and drop events
#define GLFW_DND_ENTER 0xdd100001
#define GLFW_DND_DRAG 0xdd100002
#define GLFW_DND_LEAVE 0xdd100003
// Drag and drop actions
// GLFW_DND_NONE
#define GLFW_DND_COPY 0xdd200001
#define GLFW_DND_LINK 0xdd200002
#define GLFW_DND_MOVE 0xdd200004
// Drag and drop formats
// GLFW_DND_NONE
#define GLFW_DND_TEXT 0xdd300002
#define GLFW_DND_PATHS 0xdd300001
#define GLFW_DONT_CARE -1
@ -1884,6 +1906,9 @@ typedef void (* GLFWcharfun)(GLFWwindow* window, unsigned int codepoint);
*/
typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int mods);
// TODO doc
typedef void (* GLFWdragfun)(GLFWwindow* window, int event, double xpos, double ypos, int availableFormats, int *format, int availableActions, int *action);
/*! @brief The function pointer type for path drop callbacks.
*
* This is the function pointer type for path drop callbacks. A path drop
@ -1908,6 +1933,9 @@ typedef void (* GLFWcharmodsfun)(GLFWwindow* window, unsigned int codepoint, int
*/
typedef void (* GLFWdropfun)(GLFWwindow* window, int path_count, const char* paths[]);
// TODO doc
typedef void (* GLFWdropfunex)(GLFWwindow* window, int format, int data_count, void *data, int *action);
/*! @brief The function pointer type for monitor configuration callbacks.
*
* This is the function pointer type for monitor configuration callbacks.
@ -5293,6 +5321,9 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu
*/
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
// TODO doc
GLFWAPI GLFWdragfun glfwSetDragCallback(GLFWwindow* window, GLFWdragfun callback);
/*! @brief Sets the path drop callback.
*
* This function sets the path drop callback of the specified window, which is
@ -5330,6 +5361,9 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun ca
*/
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback);
// TODO doc
GLFWAPI GLFWdropfunex glfwSetDropCallbackEx(GLFWwindow* window, GLFWdropfunex callback);
/*! @brief Returns whether the specified joystick is present.
*
* This function returns whether the specified joystick is present.

View File

@ -266,6 +266,41 @@ float _glfw_fmaxf(float a, float b)
return b;
}
int _glfw_ffs(int i)
{
#if defined(__GNUC__) || defined(__clang__)
return __builtin_ffs(i);
#elif defined(_MSC_VER)
unsigned long n, u = i;
return _BitScanForward(&n, u) ? n + 1 : 0;
#else
// https://en.wikipedia.org/wiki/Find_first_set#CTZ
unsigned int u = i;
int n = 1;
if (!u) return 0;
if (!(u & 0x0000FFFF)) {
n += 16;
u >>= 16;
}
if (!(u & 0x000000FF)) {
n += 8;
u >>= 8;
}
if (!(u & 0x0000000F)) {
n += 4;
u >>= 4;
}
if (!(u & 0x00000003)) {
n += 2;
u >>= 2;
}
if (!(u & 0x00000001)) {
n += 1;
}
return n;
#endif
}
void* _glfw_calloc(size_t count, size_t size)
{
if (count && size)

View File

@ -401,6 +401,14 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
}
// Notifies shared code of data being dragged in/over/out of a window
//
void _glfwInputDrag(_GLFWwindow* window, int event, double xpos, double ypos, int availableFormats, int *format, int availableActions, int *action)
{
if (window->callbacks.drag)
window->callbacks.drag((GLFWwindow*) window, event, xpos, ypos, availableFormats, format, availableActions, action);
}
// Notifies shared code of files or directories dropped on a window
//
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
@ -413,6 +421,14 @@ void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
window->callbacks.drop((GLFWwindow*) window, count, paths);
}
// Notifies shared code of data dropped on a window
//
void _glfwInputDropEx(_GLFWwindow* window, int format, int data_count, void *data, int *action)
{
if (window->callbacks.dropex)
window->callbacks.dropex((GLFWwindow*) window, format, data_count, data, action);
}
// Notifies shared code of a joystick connection or disconnection
//
void _glfwInputJoystick(_GLFWjoystick* js, int event)
@ -1012,6 +1028,16 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
return cbfun;
}
GLFWAPI GLFWdragfun glfwSetDragCallback(GLFWwindow* handle, GLFWdragfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWdragfun, window->callbacks.drag, cbfun);
return cbfun;
}
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
@ -1022,6 +1048,16 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
return cbfun;
}
GLFWAPI GLFWdropfunex glfwSetDropCallbackEx(GLFWwindow* handle, GLFWdropfunex cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP(GLFWdropfunex, window->callbacks.dropex, cbfun);
return cbfun;
}
GLFWAPI int glfwJoystickPresent(int jid)
{
_GLFWjoystick* js;

View File

@ -58,6 +58,17 @@
#define _GLFW_MESSAGE_SIZE 1024
#define _GLFW_DND_MASK 0x000fffff
#define _GLFW_DND_TEXT_INDEX 1
#define _GLFW_DND_PATHS_INDEX 0
#define _GLFW_DND_FORMAT_COUNT 2
#define _GLFW_DND_COPY_INDEX 0
#define _GLFW_DND_LINK_INDEX 1
#define _GLFW_DND_MOVE_INDEX 2
#define _GLFW_DND_ACTION_COUNT 3
typedef int GLFWbool;
typedef void (*GLFWproc)(void);
@ -533,6 +544,7 @@ struct _GLFWwindow
GLFWbool floating;
GLFWbool focusOnShow;
GLFWbool mousePassthrough;
GLFWbool dndDragging;
GLFWbool shouldClose;
void* userPointer;
GLFWbool doublebuffer;
@ -573,7 +585,9 @@ struct _GLFWwindow
GLFWkeyfun key;
GLFWcharfun character;
GLFWcharmodsfun charmods;
GLFWdragfun drag;
GLFWdropfun drop;
GLFWdropfunex dropex;
} callbacks;
// This is defined in platform.h
@ -928,7 +942,9 @@ void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset);
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered);
void _glfwInputDrag(_GLFWwindow* window, int event, double xpos, double ypos, int availableFormats, int *format, int availableActions, int *action);
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
void _glfwInputDropEx(_GLFWwindow* window, int format, int data_count, void *data, int *action);
void _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value);
@ -1007,6 +1023,7 @@ int _glfw_min(int a, int b);
int _glfw_max(int a, int b);
float _glfw_fminf(float a, float b);
float _glfw_fmaxf(float a, float b);
int _glfw_ffs(int i);
void* _glfw_calloc(size_t count, size_t size);
void* _glfw_realloc(void* pointer, size_t size);

View File

@ -167,6 +167,19 @@ static GLFWbool loadLibraries(void)
_glfwPlatformGetModuleSymbol(_glfw.win32.ntdll.instance, "RtlVerifyVersionInfo");
}
_glfw.win32.ole32.instance = _glfwPlatformLoadModule("ole32.dll");
if (_glfw.win32.ole32.instance)
{
_glfw.win32.ole32.OleInitialize_ = (PFN_OleInitialize)
_glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "OleInitialize");
_glfw.win32.ole32.OleUninitialize_ = (PFN_OleUninitialize)
_glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "OleUninitialize");
_glfw.win32.ole32.RegisterDragDrop_ = (PFN_RegisterDragDrop)
_glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "RegisterDragDrop");
_glfw.win32.ole32.RevokeDragDrop_ = (PFN_RevokeDragDrop)
_glfwPlatformGetModuleSymbol(_glfw.win32.ole32.instance, "RevokeDragDrop");
}
return GLFW_TRUE;
}
@ -191,6 +204,9 @@ static void freeLibraries(void)
if (_glfw.win32.ntdll.instance)
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
if (_glfw.win32.ole32.instance)
_glfwPlatformFreeModule(_glfw.win32.ole32.instance);
}
// Create key code translation tables
@ -430,6 +446,27 @@ static GLFWbool createHelperWindow(void)
return GLFW_TRUE;
}
// Initialize OLE as well as the IDropTarget vtable
//
static GLFWbool initDragDrop()
{
if (FAILED(OleInitialize(NULL)))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to initialize OLE");
return GLFW_FALSE;
}
//_glfw.win32.dropTargetVtbl.QueryInterface = _glfwDropTarget_QueryInterface;
_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;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
@ -699,6 +736,9 @@ int _glfwInitWin32(void)
if (!createHelperWindow())
return GLFW_FALSE;
if (!initDragDrop())
return GLFW_FALSE;
_glfwPollMonitorsWin32();
return GLFW_TRUE;
}
@ -708,6 +748,8 @@ void _glfwTerminateWin32(void)
if (_glfw.win32.deviceNotificationHandle)
UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
OleUninitialize();
if (_glfw.win32.helperWindowHandle)
DestroyWindow(_glfw.win32.helperWindowHandle);
if (_glfw.win32.helperWindowClass)

View File

@ -64,11 +64,15 @@
// GLFW uses OEM cursor resources
#define OEMRESOURCE
// define COM C object macros
#define COBJMACROS
#include <wctype.h>
#include <windows.h>
#include <dinput.h>
#include <xinput.h>
#include <dbt.h>
#include <ole2.h>
// HACK: Define macros that some windows.h variants don't
#ifndef WM_MOUSEHWHEEL
@ -316,6 +320,16 @@ typedef HRESULT (WINAPI * PFN_GetDpiForMonitor)(HMONITOR,MONITOR_DPI_TYPE,UINT*,
typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_
// ole32.dll function pointer typedefs
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);
#define OleInitialize _glfw.win32.ole32.OleInitialize_
#define OleUninitialize _glfw.win32.ole32.OleUninitialize_
#define RegisterDragDrop _glfw.win32.ole32.RegisterDragDrop_
#define RevokeDragDrop _glfw.win32.ole32.RevokeDragDrop_
// WGL extension pointer typedefs
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
@ -408,6 +422,18 @@ typedef struct _GLFWlibraryWGL
GLFWbool ARB_context_flush_control;
} _GLFWlibraryWGL;
typedef struct _GLFWdroptarget
{
IDropTargetVtbl* lpVtbl;
ULONG cRefCount;
_GLFWwindow* window;
int availableFormats;
int chosenFormat;
int availableActions;
int proposedAction;
int chosenAction;
} _GLFWdroptarget;
// Win32-specific per-window data
//
typedef struct _GLFWwindowWin32
@ -432,6 +458,8 @@ typedef struct _GLFWwindowWin32
int lastCursorPosX, lastCursorPosY;
// The last received high surrogate when decoding pairs of UTF-16 messages
WCHAR highSurrogate;
_GLFWdroptarget dropTarget;
} _GLFWwindowWin32;
// Win32-specific global data
@ -457,6 +485,7 @@ typedef struct _GLFWlibraryWin32
RAWINPUT* rawInput;
int rawInputSize;
UINT mouseTrailSize;
IDropTargetVtbl dropTargetVtbl;
struct {
HINSTANCE instance;
@ -499,6 +528,15 @@ typedef struct _GLFWlibraryWin32
HINSTANCE instance;
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
} ntdll;
struct {
HINSTANCE instance;
PFN_OleInitialize OleInitialize_;
PFN_OleUninitialize OleUninitialize_;
PFN_RegisterDragDrop RegisterDragDrop_;
PFN_RevokeDragDrop RevokeDragDrop_;
} ole32;
} _GLFWlibraryWin32;
// Win32-specific per-monitor data
@ -622,3 +660,11 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig);
// IDropTarget vtable functions
//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

@ -30,6 +30,7 @@
#include "internal.h"
#include <limits.h>
#include <stdio.h> // TODO remove
#include <stdlib.h>
#include <string.h>
#include <windowsx.h>
@ -1426,7 +1427,15 @@ static int createNativeWindow(_GLFWwindow* window,
}
}
DragAcceptFiles(window->win32.handle, TRUE);
//DragAcceptFiles(window->win32.handle, TRUE);
window->win32.dropTarget.lpVtbl = &_glfw.win32.dropTargetVtbl;
window->win32.dropTarget.window = window;
if (FAILED(RegisterDragDrop(window->win32.handle, (LPDROPTARGET)&window->win32.dropTarget)))
{
_glfwInputErrorWin32(GLFW_PLATFORM_ERROR,
"Win32: Failed to register window for drag & drop");
return GLFW_FALSE;
}
if (fbconfig->transparent)
{
@ -1515,6 +1524,8 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window)
if (_glfw.win32.capturedCursorWindow == window)
releaseCursor();
RevokeDragDrop(window->win32.handle);
if (window->win32.handle)
{
RemovePropW(window->win32.handle, L"GLFW");
@ -2500,3 +2511,232 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
return window->win32.handle;
}
/*static GLFWbool _glfwIsEqualIID(REFIID riid1, REFIID riid2)
{
return riid1->Data1 == riid2->Data1
&& riid1->Data2 == riid2->Data2
&& riid1->Data3 == riid2->Data3
&& (memcmp(riid1->Data4, riid2->Data4, sizeof(riid1->Data4)) == 0);
}
// IDropTarget vtable functions
HRESULT STDMETHODCALLTYPE _glfwDropTarget_QueryInterface(IDropTarget *_This, REFIID riid, void **ppvObject)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_QueryInterface\n");
if(!ppvObject)
return E_POINTER;
if (_glfwIsEqualIID(riid, &IID_IUnknown) || _glfwIsEqualIID(riid, &IID_IDropTarget))
{
*ppvObject = This;
This->lpVtbl->AddRef(This);
return S_OK;
}
*ppvObject = 0;
return E_NOINTERFACE;
}*/
// 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(IDropTarget *_This)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_Release\n");
return --This->cRefCount;
}
HRESULT STDMETHODCALLTYPE _glfwDropTarget_DragEnter(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
FORMATETC fmt = { 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
printf("DropTarget_DragEnter\n");
getActions(This, *pdwEffect);
This->availableFormats = GLFW_DND_NONE;
if (SUCCEEDED(IDataObject_QueryGetData(pDataObj, withClipFormat(&fmt, CF_HDROP)))
&& SUCCEEDED(IDataObject_GetData(pDataObj, &fmt, &stgmed)))
{
This->availableFormats |= GLFW_DND_PATHS;
printf("paths\n");
}
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(IDropTarget *_This, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
printf("DropTarget_DragOver\n");
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(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(IDropTarget *_This, IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
{
_GLFWdroptarget *This = (_GLFWdroptarget*) _This;
FORMATETC fmt = { 0, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM stgmed;
printf("DropTarget_Drop\n");
*pdwEffect = DROPEFFECT_NONE;
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 (paths)\n");
_glfwInputCursorPos(This->window, pt.x, pt.y);
for (i = 0; i < count; ++i)
{
const UINT length = DragQueryFileW(drop, i, NULL, 0);
WCHAR* buffer = _glfw_calloc((size_t) length + 1, sizeof(WCHAR));
DragQueryFileW(drop, i, buffer, length + 1);
paths[i] = _glfwCreateUTF8FromWideStringWin32(buffer);
_glfw_free(buffer);
}
_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);
setActions(This, pdwEffect);
return S_OK;
}

View File

@ -860,6 +860,8 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* handle, int attrib)
return window->focusOnShow;
case GLFW_MOUSE_PASSTHROUGH:
return window->mousePassthrough;
case GLFW_DND_DRAGGING:
return window->dndDragging;
case GLFW_TRANSPARENT_FRAMEBUFFER:
return _glfw.platform.framebufferTransparent(window);
case GLFW_RESIZABLE:

View File

@ -910,11 +910,6 @@ static GLFWbool initExtensions(void)
// the keyboard mapping.
createKeyTables();
// String format atoms
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
_glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
_glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
// Custom selection property atom
_glfw.x11.GLFW_SELECTION =
XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False);
@ -925,6 +920,7 @@ static GLFWbool initExtensions(void)
_glfw.x11.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
_glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
_glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
_glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
// Clipboard manager atoms
_glfw.x11.CLIPBOARD_MANAGER =
@ -937,11 +933,24 @@ static GLFWbool initExtensions(void)
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
_glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
_glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", False);
_glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
_glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False);
_glfw.x11.XdndActions[_GLFW_DND_COPY_INDEX] =
XInternAtom(_glfw.x11.display, "XdndActionCopy", False);
_glfw.x11.XdndActions[_GLFW_DND_LINK_INDEX] =
XInternAtom(_glfw.x11.display, "XdndActionLink", False);
_glfw.x11.XdndActions[_GLFW_DND_MOVE_INDEX] =
XInternAtom(_glfw.x11.display, "XdndActionMove", False);
_glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
_glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False);
// Format atoms (shared by Xdnd and selection)
_glfw.x11.NULL_ = XInternAtom(_glfw.x11.display, "NULL", False);
_glfw.x11.UTF8_STRING = XInternAtom(_glfw.x11.display, "UTF8_STRING", False);
_glfw.x11.STRING = XInternAtom(_glfw.x11.display, "STRING", False);
_glfw.x11.TEXT = XInternAtom(_glfw.x11.display, "TEXT", False);
_glfw.x11.text_plain = XInternAtom(_glfw.x11.display, "text/plain", False);
_glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
// ICCCM, EWMH and Motif window property atoms

View File

@ -97,6 +97,9 @@ typedef struct __GLXFBConfig* GLXFBConfig;
typedef struct __GLXcontext* GLXContext;
typedef void (*__GLXextproc)(void);
// TODO for dev; remove
typedef char* (* PFN_XGetAtomName)(Display*,Atom);
typedef XClassHint* (* PFN_XAllocClassHint)(void);
typedef XSizeHints* (* PFN_XAllocSizeHints)(void);
typedef XWMHints* (* PFN_XAllocWMHints)(void);
@ -622,12 +625,12 @@ typedef struct _GLFWlibraryX11
Atom XdndEnter;
Atom XdndPosition;
Atom XdndStatus;
Atom XdndActionCopy;
Atom XdndLeave;
Atom XdndActions[_GLFW_DND_ACTION_COUNT];
Atom XdndDrop;
Atom XdndFinished;
Atom XdndSelection;
Atom XdndTypeList;
Atom text_uri_list;
// Selection (clipboard) atoms
Atom TARGETS;
@ -637,12 +640,17 @@ typedef struct _GLFWlibraryX11
Atom PRIMARY;
Atom CLIPBOARD_MANAGER;
Atom SAVE_TARGETS;
Atom NULL_;
Atom UTF8_STRING;
Atom COMPOUND_STRING;
Atom ATOM_PAIR;
Atom GLFW_SELECTION;
// Format atoms (shared by Xdnd and Selection)
Atom NULL_;
Atom UTF8_STRING;
Atom STRING;
Atom TEXT;
Atom text_plain;
Atom text_uri_list;
struct {
void* handle;
GLFWbool utf8;
@ -800,7 +808,12 @@ typedef struct _GLFWlibraryX11
struct {
int version;
Window source;
Atom format;
Atom formatAtoms[_GLFW_DND_FORMAT_COUNT];
int availableFormats;
int chosenFormat;
int availableActions;
int proposedAction;
int chosenAction;
} xdnd;
struct {

View File

@ -1534,15 +1534,22 @@ static void processEvent(XEvent *event)
// A drag operation has entered the window
unsigned long count;
Atom* formats = NULL;
double xpos, ypos;
const GLFWbool list = event->xclient.data.l[1] & 1;
memset(&_glfw.x11.xdnd, 0, sizeof(_glfw.x11.xdnd));
_glfw.x11.xdnd.source = event->xclient.data.l[0];
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
_glfw.x11.xdnd.format = None;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
// Xdnd doesn't support the concepts "available actions" and
// "proposed action"; default to all and copy
_glfw.x11.xdnd.availableActions =
GLFW_DND_COPY | GLFW_DND_LINK | GLFW_DND_MOVE;
_glfw.x11.xdnd.proposedAction = GLFW_DND_COPY;
if (list)
{
count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source,
@ -1556,27 +1563,75 @@ static void processEvent(XEvent *event)
formats = (Atom*) event->xclient.data.l + 2;
}
// TODO remove
PFN_XGetAtomName GetAtomName = (PFN_XGetAtomName)
_glfwPlatformGetModuleSymbol(_glfw.x11.xlib.handle, "XGetAtomName");
for (unsigned int i = 0; i < count; i++)
{
if (formats[i] == _glfw.x11.text_uri_list)
printf("format (%d): %s\n", i, GetAtomName(_glfw.x11.display, formats[i]));
if (!_glfw.x11.xdnd.formatAtoms[_GLFW_DND_PATHS_INDEX]
&& formats[i] == _glfw.x11.text_uri_list)
{
_glfw.x11.xdnd.format = _glfw.x11.text_uri_list;
break;
_glfw.x11.xdnd.formatAtoms[_GLFW_DND_PATHS_INDEX] = formats[i];
_glfw.x11.xdnd.availableFormats |= GLFW_DND_PATHS;
}
else if (!_glfw.x11.xdnd.formatAtoms[_GLFW_DND_TEXT_INDEX]
&& (formats[i] == _glfw.x11.text_plain
|| formats[i] == _glfw.x11.UTF8_STRING
|| formats[i] == _glfw.x11.STRING
|| formats[i] == _glfw.x11.TEXT))
{
_glfw.x11.xdnd.formatAtoms[_GLFW_DND_TEXT_INDEX] = formats[i];
_glfw.x11.xdnd.availableFormats |= GLFW_DND_TEXT;
}
}
if (list && formats)
XFree(formats);
window->dndDragging = GLFW_TRUE;
_glfwGetCursorPosX11(window, &xpos, &ypos);
_glfw.x11.xdnd.chosenFormat = _glfw.x11.xdnd.availableFormats;
_glfw.x11.xdnd.chosenAction = _glfw.x11.xdnd.proposedAction;
_glfwInputDrag(window, GLFW_DND_ENTER, xpos, ypos,
_glfw.x11.xdnd.availableFormats,
&_glfw.x11.xdnd.chosenFormat,
_glfw.x11.xdnd.availableActions,
&_glfw.x11.xdnd.chosenAction);
}
else if (event->xclient.message_type == _glfw.x11.XdndLeave)
{
// A drag operation has left the window or was canceled
window->dndDragging = GLFW_FALSE;
_glfw.x11.xdnd.chosenFormat =
_glfw.x11.xdnd.availableFormats = GLFW_DND_NONE;
_glfw.x11.xdnd.chosenAction =
_glfw.x11.xdnd.proposedAction =
_glfw.x11.xdnd.availableActions = GLFW_DND_NONE;
_glfwInputDrag(window, GLFW_DND_LEAVE, 0.0, 0.0,
_glfw.x11.xdnd.availableFormats,
&_glfw.x11.xdnd.chosenFormat,
_glfw.x11.xdnd.availableActions,
&_glfw.x11.xdnd.chosenAction);
}
else if (event->xclient.message_type == _glfw.x11.XdndDrop)
{
// The drag operation has finished by dropping on the window
Time time = CurrentTime;
int formatIndex = _glfw_ffs(_glfw.x11.xdnd.chosenFormat
& _GLFW_DND_MASK) - 1;
window->dndDragging = GLFW_FALSE;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
if (_glfw.x11.xdnd.format)
if (_glfw.x11.xdnd.chosenAction
&& formatIndex >= 0 && formatIndex < _GLFW_DND_FORMAT_COUNT
&& _glfw.x11.xdnd.formatAtoms[formatIndex])
{
if (_glfw.x11.xdnd.version >= 1)
time = event->xclient.data.l[2];
@ -1584,7 +1639,7 @@ static void processEvent(XEvent *event)
// Request the chosen format from the source window
XConvertSelection(_glfw.x11.display,
_glfw.x11.XdndSelection,
_glfw.x11.xdnd.format,
_glfw.x11.xdnd.formatAtoms[formatIndex],
_glfw.x11.XdndSelection,
window->x11.handle,
time);
@ -1609,12 +1664,29 @@ static void processEvent(XEvent *event)
// The drag operation has moved over the window
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
const int yabs = (event->xclient.data.l[2]) & 0xffff;
const Atom action = event->xclient.data.l[4];
Window dummy;
int xpos, ypos;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return;
if (_glfw.x11.xdnd.version >= 2)
{
_glfw.x11.xdnd.proposedAction = GLFW_DND_NONE;
for(int i = 0; i < _GLFW_DND_ACTION_COUNT; ++i)
{
if(action == _glfw.x11.XdndActions[i])
{
_glfw.x11.xdnd.proposedAction =
(GLFW_DND_COPY & ~_GLFW_DND_MASK) | (1 << i);
break;
}
}
}
else
_glfw.x11.xdnd.proposedAction = GLFW_DND_COPY;
XTranslateCoordinates(_glfw.x11.display,
_glfw.x11.root,
window->x11.handle,
@ -1624,6 +1696,13 @@ static void processEvent(XEvent *event)
_glfwInputCursorPos(window, xpos, ypos);
_glfw.x11.xdnd.chosenAction = _glfw.x11.xdnd.proposedAction;
_glfwInputDrag(window, GLFW_DND_DRAG, xpos, ypos,
_glfw.x11.xdnd.availableFormats,
&_glfw.x11.xdnd.chosenFormat,
_glfw.x11.xdnd.availableActions,
&_glfw.x11.xdnd.chosenAction);
XEvent reply = { ClientMessage };
reply.xclient.window = _glfw.x11.xdnd.source;
reply.xclient.message_type = _glfw.x11.XdndStatus;
@ -1632,12 +1711,19 @@ static void processEvent(XEvent *event)
reply.xclient.data.l[2] = 0; // Specify an empty rectangle
reply.xclient.data.l[3] = 0;
if (_glfw.x11.xdnd.format)
if (_glfw.x11.xdnd.chosenAction)
{
// Reply that we are ready to copy the dragged data
reply.xclient.data.l[1] = 1; // Accept with no rectangle
if (_glfw.x11.xdnd.version >= 2)
reply.xclient.data.l[4] = _glfw.x11.XdndActionCopy;
{
int actionIndex = _glfw_ffs(_glfw.x11.xdnd.chosenAction
& _GLFW_DND_MASK) - 1;
if(actionIndex >= 0 && actionIndex < _GLFW_DND_ACTION_COUNT)
{
reply.xclient.data.l[4] = _glfw.x11.XdndActions[actionIndex];
}
}
}
XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
@ -1662,14 +1748,38 @@ static void processEvent(XEvent *event)
if (result)
{
int count;
char** paths = _glfwParseUriList(data, &count);
int formatIndex = _glfw_ffs(_glfw.x11.xdnd.chosenFormat
& _GLFW_DND_MASK) - 1;
if(formatIndex >= 0 && formatIndex < _GLFW_DND_FORMAT_COUNT)
{
int format = (GLFW_DND_TEXT & ~_GLFW_DND_MASK) | (1 << formatIndex);
switch (format)
{
case GLFW_DND_PATHS:
{
int count;
char** paths = _glfwParseUriList(data, &count);
_glfwInputDrop(window, count, (const char**) paths);
_glfwInputDrop(window, count, (const char **) paths);
for (int i = 0; i < count; i++)
_glfw_free(paths[i]);
_glfw_free(paths);
_glfwInputDropEx(window, format, count, paths,
&_glfw.x11.xdnd.chosenAction);
for (int i = 0; i < count; ++i)
_glfw_free(paths[i]);
_glfw_free(paths);
break;
}
case GLFW_DND_TEXT:
{
_glfwInputDropEx(window, format, -1, data,
&_glfw.x11.xdnd.chosenAction);
break;
}
default:
break;
}
}
}
if (data)
@ -1683,7 +1793,13 @@ static void processEvent(XEvent *event)
reply.xclient.format = 32;
reply.xclient.data.l[0] = window->x11.handle;
reply.xclient.data.l[1] = result;
reply.xclient.data.l[2] = _glfw.x11.XdndActionCopy;
int actionIndex = _glfw_ffs(_glfw.x11.xdnd.chosenAction
& _GLFW_DND_MASK) - 1;
if(actionIndex >= 0 && actionIndex < _GLFW_DND_ACTION_COUNT)
{
reply.xclient.data.l[2] = _glfw.x11.XdndActions[actionIndex];
}
XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
False, NoEventMask, &reply);