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); 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) int main(void)
{ {
(void)setvbuf(stdout, NULL, _IONBF, 0);
(void)setvbuf(stderr, NULL, _IONBF, 0);
glfwSetErrorCallback(error_callback); glfwSetErrorCallback(error_callback);
if (!glfwInit()) if (!glfwInit())
@ -99,6 +180,9 @@ int main(void)
} }
glfwSetKeyCallback(window, key_callback); glfwSetKeyCallback(window, key_callback);
glfwSetDragCallback(window, drag_callback);
glfwSetDropCallback(window, drop_callback);
glfwSetDropCallbackEx(window, dropex_callback);
glfwMakeContextCurrent(window); glfwMakeContextCurrent(window);
gladLoadGL(glfwGetProcAddress); gladLoadGL(glfwGetProcAddress);
@ -149,6 +233,7 @@ int main(void)
mat4x4 m, p, mvp; mat4x4 m, p, mvp;
mat4x4_identity(m); mat4x4_identity(m);
if (glfwGetWindowAttrib(window, GLFW_DND_DRAGGING))
mat4x4_rotate_Z(m, m, (float) glfwGetTime()); mat4x4_rotate_Z(m, m, (float) glfwGetTime());
mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f); mat4x4_ortho(p, -ratio, ratio, -1.f, 1.f, 1.f, -1.f);
mat4x4_mul(mvp, p, m); mat4x4_mul(mvp, p, m);

View File

@ -927,6 +927,9 @@ extern "C" {
*/ */
#define GLFW_MOUSE_PASSTHROUGH 0x0002000D #define GLFW_MOUSE_PASSTHROUGH 0x0002000D
// TODO doc
#define GLFW_DND_DRAGGING 0x0002000E
/*! @brief Framebuffer bit depth hint. /*! @brief Framebuffer bit depth hint.
* *
* Framebuffer bit depth [hint](@ref GLFW_RED_BITS). * Framebuffer bit depth [hint](@ref GLFW_RED_BITS).
@ -1309,6 +1312,25 @@ extern "C" {
#define GLFW_PLATFORM_NULL 0x00060005 #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 #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); 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. /*! @brief The function pointer type for path drop callbacks.
* *
* This is the function pointer type for path drop callbacks. A path drop * 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[]); 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. /*! @brief The function pointer type for monitor configuration callbacks.
* *
* This is 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); GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun callback);
// TODO doc
GLFWAPI GLFWdragfun glfwSetDragCallback(GLFWwindow* window, GLFWdragfun callback);
/*! @brief Sets the path drop callback. /*! @brief Sets the path drop callback.
* *
* This function sets the path drop callback of the specified window, which is * 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); GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun callback);
// TODO doc
GLFWAPI GLFWdropfunex glfwSetDropCallbackEx(GLFWwindow* window, GLFWdropfunex callback);
/*! @brief Returns whether the specified joystick is present. /*! @brief Returns whether the specified joystick is present.
* *
* This function 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; 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) void* _glfw_calloc(size_t count, size_t size)
{ {
if (count && size) if (count && size)

View File

@ -401,6 +401,14 @@ void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
window->callbacks.cursorEnter((GLFWwindow*) window, 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 // Notifies shared code of files or directories dropped on a window
// //
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) 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); 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 // Notifies shared code of a joystick connection or disconnection
// //
void _glfwInputJoystick(_GLFWjoystick* js, int event) void _glfwInputJoystick(_GLFWjoystick* js, int event)
@ -1012,6 +1028,16 @@ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
return cbfun; 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) GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
{ {
_GLFWwindow* window = (_GLFWwindow*) handle; _GLFWwindow* window = (_GLFWwindow*) handle;
@ -1022,6 +1048,16 @@ GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
return 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) GLFWAPI int glfwJoystickPresent(int jid)
{ {
_GLFWjoystick* js; _GLFWjoystick* js;

View File

@ -58,6 +58,17 @@
#define _GLFW_MESSAGE_SIZE 1024 #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 int GLFWbool;
typedef void (*GLFWproc)(void); typedef void (*GLFWproc)(void);
@ -533,6 +544,7 @@ struct _GLFWwindow
GLFWbool floating; GLFWbool floating;
GLFWbool focusOnShow; GLFWbool focusOnShow;
GLFWbool mousePassthrough; GLFWbool mousePassthrough;
GLFWbool dndDragging;
GLFWbool shouldClose; GLFWbool shouldClose;
void* userPointer; void* userPointer;
GLFWbool doublebuffer; GLFWbool doublebuffer;
@ -573,7 +585,9 @@ struct _GLFWwindow
GLFWkeyfun key; GLFWkeyfun key;
GLFWcharfun character; GLFWcharfun character;
GLFWcharmodsfun charmods; GLFWcharmodsfun charmods;
GLFWdragfun drag;
GLFWdropfun drop; GLFWdropfun drop;
GLFWdropfunex dropex;
} callbacks; } callbacks;
// This is defined in platform.h // 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 _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods);
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos);
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered); 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 _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 _glfwInputJoystick(_GLFWjoystick* js, int event);
void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value); void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value);
void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char 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); int _glfw_max(int a, int b);
float _glfw_fminf(float a, float b); float _glfw_fminf(float a, float b);
float _glfw_fmaxf(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_calloc(size_t count, size_t size);
void* _glfw_realloc(void* pointer, 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"); _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; return GLFW_TRUE;
} }
@ -191,6 +204,9 @@ static void freeLibraries(void)
if (_glfw.win32.ntdll.instance) if (_glfw.win32.ntdll.instance)
_glfwPlatformFreeModule(_glfw.win32.ntdll.instance); _glfwPlatformFreeModule(_glfw.win32.ntdll.instance);
if (_glfw.win32.ole32.instance)
_glfwPlatformFreeModule(_glfw.win32.ole32.instance);
} }
// Create key code translation tables // Create key code translation tables
@ -430,6 +446,27 @@ static GLFWbool createHelperWindow(void)
return GLFW_TRUE; 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 ////// ////// GLFW internal API //////
@ -699,6 +736,9 @@ int _glfwInitWin32(void)
if (!createHelperWindow()) if (!createHelperWindow())
return GLFW_FALSE; return GLFW_FALSE;
if (!initDragDrop())
return GLFW_FALSE;
_glfwPollMonitorsWin32(); _glfwPollMonitorsWin32();
return GLFW_TRUE; return GLFW_TRUE;
} }
@ -708,6 +748,8 @@ void _glfwTerminateWin32(void)
if (_glfw.win32.deviceNotificationHandle) if (_glfw.win32.deviceNotificationHandle)
UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle); UnregisterDeviceNotification(_glfw.win32.deviceNotificationHandle);
OleUninitialize();
if (_glfw.win32.helperWindowHandle) if (_glfw.win32.helperWindowHandle)
DestroyWindow(_glfw.win32.helperWindowHandle); DestroyWindow(_glfw.win32.helperWindowHandle);
if (_glfw.win32.helperWindowClass) if (_glfw.win32.helperWindowClass)

View File

@ -64,11 +64,15 @@
// GLFW uses OEM cursor resources // GLFW uses OEM cursor resources
#define OEMRESOURCE #define OEMRESOURCE
// define COM C object macros
#define COBJMACROS
#include <wctype.h> #include <wctype.h>
#include <windows.h> #include <windows.h>
#include <dinput.h> #include <dinput.h>
#include <xinput.h> #include <xinput.h>
#include <dbt.h> #include <dbt.h>
#include <ole2.h>
// HACK: Define macros that some windows.h variants don't // HACK: Define macros that some windows.h variants don't
#ifndef WM_MOUSEHWHEEL #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); typedef LONG (WINAPI * PFN_RtlVerifyVersionInfo)(OSVERSIONINFOEXW*,ULONG,ULONGLONG);
#define RtlVerifyVersionInfo _glfw.win32.ntdll.RtlVerifyVersionInfo_ #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 // WGL extension pointer typedefs
typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*); typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
@ -408,6 +422,18 @@ typedef struct _GLFWlibraryWGL
GLFWbool ARB_context_flush_control; GLFWbool ARB_context_flush_control;
} _GLFWlibraryWGL; } _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 // Win32-specific per-window data
// //
typedef struct _GLFWwindowWin32 typedef struct _GLFWwindowWin32
@ -432,6 +458,8 @@ typedef struct _GLFWwindowWin32
int lastCursorPosX, lastCursorPosY; int lastCursorPosX, lastCursorPosY;
// 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;
} _GLFWwindowWin32; } _GLFWwindowWin32;
// Win32-specific global data // Win32-specific global data
@ -457,6 +485,7 @@ typedef struct _GLFWlibraryWin32
RAWINPUT* rawInput; RAWINPUT* rawInput;
int rawInputSize; int rawInputSize;
UINT mouseTrailSize; UINT mouseTrailSize;
IDropTargetVtbl dropTargetVtbl;
struct { struct {
HINSTANCE instance; HINSTANCE instance;
@ -499,6 +528,15 @@ typedef struct _GLFWlibraryWin32
HINSTANCE instance; HINSTANCE instance;
PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_; PFN_RtlVerifyVersionInfo RtlVerifyVersionInfo_;
} ntdll; } ntdll;
struct {
HINSTANCE instance;
PFN_OleInitialize OleInitialize_;
PFN_OleUninitialize OleUninitialize_;
PFN_RegisterDragDrop RegisterDragDrop_;
PFN_RevokeDragDrop RevokeDragDrop_;
} ole32;
} _GLFWlibraryWin32; } _GLFWlibraryWin32;
// Win32-specific per-monitor data // Win32-specific per-monitor data
@ -622,3 +660,11 @@ GLFWbool _glfwCreateContextWGL(_GLFWwindow* window,
const _GLFWctxconfig* ctxconfig, const _GLFWctxconfig* ctxconfig,
const _GLFWfbconfig* fbconfig); 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 "internal.h"
#include <limits.h> #include <limits.h>
#include <stdio.h> // TODO remove
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <windowsx.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) if (fbconfig->transparent)
{ {
@ -1515,6 +1524,8 @@ void _glfwDestroyWindowWin32(_GLFWwindow* window)
if (_glfw.win32.capturedCursorWindow == window) if (_glfw.win32.capturedCursorWindow == window)
releaseCursor(); releaseCursor();
RevokeDragDrop(window->win32.handle);
if (window->win32.handle) if (window->win32.handle)
{ {
RemovePropW(window->win32.handle, L"GLFW"); RemovePropW(window->win32.handle, L"GLFW");
@ -2500,3 +2511,232 @@ GLFWAPI HWND glfwGetWin32Window(GLFWwindow* handle)
return window->win32.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; return window->focusOnShow;
case GLFW_MOUSE_PASSTHROUGH: case GLFW_MOUSE_PASSTHROUGH:
return window->mousePassthrough; return window->mousePassthrough;
case GLFW_DND_DRAGGING:
return window->dndDragging;
case GLFW_TRANSPARENT_FRAMEBUFFER: case GLFW_TRANSPARENT_FRAMEBUFFER:
return _glfw.platform.framebufferTransparent(window); return _glfw.platform.framebufferTransparent(window);
case GLFW_RESIZABLE: case GLFW_RESIZABLE:

View File

@ -910,11 +910,6 @@ static GLFWbool initExtensions(void)
// the keyboard mapping. // the keyboard mapping.
createKeyTables(); 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 // Custom selection property atom
_glfw.x11.GLFW_SELECTION = _glfw.x11.GLFW_SELECTION =
XInternAtom(_glfw.x11.display, "GLFW_SELECTION", False); 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.PRIMARY = XInternAtom(_glfw.x11.display, "PRIMARY", False);
_glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False); _glfw.x11.INCR = XInternAtom(_glfw.x11.display, "INCR", False);
_glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False); _glfw.x11.CLIPBOARD = XInternAtom(_glfw.x11.display, "CLIPBOARD", False);
_glfw.x11.ATOM_PAIR = XInternAtom(_glfw.x11.display, "ATOM_PAIR", False);
// Clipboard manager atoms // Clipboard manager atoms
_glfw.x11.CLIPBOARD_MANAGER = _glfw.x11.CLIPBOARD_MANAGER =
@ -937,11 +933,24 @@ static GLFWbool initExtensions(void)
_glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False); _glfw.x11.XdndEnter = XInternAtom(_glfw.x11.display, "XdndEnter", False);
_glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False); _glfw.x11.XdndPosition = XInternAtom(_glfw.x11.display, "XdndPosition", False);
_glfw.x11.XdndStatus = XInternAtom(_glfw.x11.display, "XdndStatus", 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.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False);
_glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False);
_glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False);
_glfw.x11.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", 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); _glfw.x11.text_uri_list = XInternAtom(_glfw.x11.display, "text/uri-list", False);
// ICCCM, EWMH and Motif window property atoms // ICCCM, EWMH and Motif window property atoms

View File

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

View File

@ -1534,15 +1534,22 @@ static void processEvent(XEvent *event)
// A drag operation has entered the window // A drag operation has entered the window
unsigned long count; unsigned long count;
Atom* formats = NULL; Atom* formats = NULL;
double xpos, ypos;
const GLFWbool list = event->xclient.data.l[1] & 1; 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.source = event->xclient.data.l[0];
_glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24; _glfw.x11.xdnd.version = event->xclient.data.l[1] >> 24;
_glfw.x11.xdnd.format = None;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return; 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) if (list)
{ {
count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source, count = _glfwGetWindowPropertyX11(_glfw.x11.xdnd.source,
@ -1556,27 +1563,75 @@ static void processEvent(XEvent *event)
formats = (Atom*) event->xclient.data.l + 2; 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++) 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; _glfw.x11.xdnd.formatAtoms[_GLFW_DND_PATHS_INDEX] = formats[i];
break; _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) if (list && formats)
XFree(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) else if (event->xclient.message_type == _glfw.x11.XdndDrop)
{ {
// The drag operation has finished by dropping on the window // The drag operation has finished by dropping on the window
Time time = CurrentTime; 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) if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return; 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) if (_glfw.x11.xdnd.version >= 1)
time = event->xclient.data.l[2]; time = event->xclient.data.l[2];
@ -1584,7 +1639,7 @@ static void processEvent(XEvent *event)
// Request the chosen format from the source window // Request the chosen format from the source window
XConvertSelection(_glfw.x11.display, XConvertSelection(_glfw.x11.display,
_glfw.x11.XdndSelection, _glfw.x11.XdndSelection,
_glfw.x11.xdnd.format, _glfw.x11.xdnd.formatAtoms[formatIndex],
_glfw.x11.XdndSelection, _glfw.x11.XdndSelection,
window->x11.handle, window->x11.handle,
time); time);
@ -1609,12 +1664,29 @@ static void processEvent(XEvent *event)
// The drag operation has moved over the window // The drag operation has moved over the window
const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff; const int xabs = (event->xclient.data.l[2] >> 16) & 0xffff;
const int yabs = (event->xclient.data.l[2]) & 0xffff; const int yabs = (event->xclient.data.l[2]) & 0xffff;
const Atom action = event->xclient.data.l[4];
Window dummy; Window dummy;
int xpos, ypos; int xpos, ypos;
if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION) if (_glfw.x11.xdnd.version > _GLFW_XDND_VERSION)
return; 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, XTranslateCoordinates(_glfw.x11.display,
_glfw.x11.root, _glfw.x11.root,
window->x11.handle, window->x11.handle,
@ -1624,6 +1696,13 @@ static void processEvent(XEvent *event)
_glfwInputCursorPos(window, xpos, ypos); _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 }; XEvent reply = { ClientMessage };
reply.xclient.window = _glfw.x11.xdnd.source; reply.xclient.window = _glfw.x11.xdnd.source;
reply.xclient.message_type = _glfw.x11.XdndStatus; 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[2] = 0; // Specify an empty rectangle
reply.xclient.data.l[3] = 0; 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 that we are ready to copy the dragged data
reply.xclient.data.l[1] = 1; // Accept with no rectangle reply.xclient.data.l[1] = 1; // Accept with no rectangle
if (_glfw.x11.xdnd.version >= 2) 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, XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
@ -1661,15 +1747,39 @@ static void processEvent(XEvent *event)
(unsigned char**) &data); (unsigned char**) &data);
if (result) if (result)
{
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; int count;
char** paths = _glfwParseUriList(data, &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++) _glfwInputDropEx(window, format, count, paths,
&_glfw.x11.xdnd.chosenAction);
for (int i = 0; i < count; ++i)
_glfw_free(paths[i]); _glfw_free(paths[i]);
_glfw_free(paths); _glfw_free(paths);
break;
}
case GLFW_DND_TEXT:
{
_glfwInputDropEx(window, format, -1, data,
&_glfw.x11.xdnd.chosenAction);
break;
}
default:
break;
}
}
} }
if (data) if (data)
@ -1683,7 +1793,13 @@ static void processEvent(XEvent *event)
reply.xclient.format = 32; reply.xclient.format = 32;
reply.xclient.data.l[0] = window->x11.handle; reply.xclient.data.l[0] = window->x11.handle;
reply.xclient.data.l[1] = result; 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, XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.source,
False, NoEventMask, &reply); False, NoEventMask, &reply);