mirror of
https://github.com/glfw/glfw.git
synced 2025-06-08 00:34:56 +00:00
Merge d010d61f87
into 3a60992a41
This commit is contained in:
commit
0ad98d3f74
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
35
src/init.c
35
src/init.c
@ -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)
|
||||
|
36
src/input.c
36
src/input.c
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
146
src/x11_window.c
146
src/x11_window.c
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user