Cleaned up drop callback design.
This commit is contained in:
parent
ed4c8b27f1
commit
8f349e84ae
@ -46,6 +46,7 @@ The following dependencies are needed by the examples and test programs:
|
|||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
- Added native monitor handle access to native API
|
- Added native monitor handle access to native API
|
||||||
|
- Added `glfwSetDropCallback` and `GLFWdropfun` for receiving dropped files
|
||||||
- [Cocoa] Bugfix: Using a 1x1 cursor for hidden mode caused some screen
|
- [Cocoa] Bugfix: Using a 1x1 cursor for hidden mode caused some screen
|
||||||
recorders to fail
|
recorders to fail
|
||||||
|
|
||||||
|
@ -779,13 +779,14 @@ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int);
|
|||||||
* This is the function signature for drop callbacks.
|
* This is the function signature for drop callbacks.
|
||||||
*
|
*
|
||||||
* @param[in] window The window that received the event.
|
* @param[in] window The window that received the event.
|
||||||
* @param[in] string The string descriptor for the dropped object.
|
* @param[in] count The number of dropped objects.
|
||||||
|
* @param[in] names The names of the dropped object.
|
||||||
*
|
*
|
||||||
* @sa glfwSetDropCallback
|
* @sa glfwSetDropCallback
|
||||||
*
|
*
|
||||||
* @ingroup input
|
* @ingroup input
|
||||||
*/
|
*/
|
||||||
typedef void (* GLFWdropfun)(GLFWwindow*,const char*);
|
typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**);
|
||||||
|
|
||||||
/*! @brief The function signature for monitor configuration callbacks.
|
/*! @brief The function signature for monitor configuration callbacks.
|
||||||
*
|
*
|
||||||
|
@ -413,8 +413,6 @@ static int translateKey(unsigned int key)
|
|||||||
@interface GLFWContentView : NSView
|
@interface GLFWContentView : NSView
|
||||||
{
|
{
|
||||||
_GLFWwindow* window;
|
_GLFWwindow* window;
|
||||||
char * fileNamesForDrag;
|
|
||||||
int fileNamesSize;
|
|
||||||
NSTrackingArea* trackingArea;
|
NSTrackingArea* trackingArea;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,9 +444,6 @@ static int translateKey(unsigned int key)
|
|||||||
window = initWindow;
|
window = initWindow;
|
||||||
trackingArea = nil;
|
trackingArea = nil;
|
||||||
|
|
||||||
fileNamesForDrag = malloc(1024);
|
|
||||||
fileNamesSize = 1024;
|
|
||||||
|
|
||||||
[self updateTrackingAreas];
|
[self updateTrackingAreas];
|
||||||
[self registerForDraggedTypes:[NSArray arrayWithObjects:
|
[self registerForDraggedTypes:[NSArray arrayWithObjects:
|
||||||
NSFilenamesPboardType, nil]];
|
NSFilenamesPboardType, nil]];
|
||||||
@ -460,7 +455,6 @@ static int translateKey(unsigned int key)
|
|||||||
-(void)dealloc
|
-(void)dealloc
|
||||||
{
|
{
|
||||||
[trackingArea release];
|
[trackingArea release];
|
||||||
free(fileNamesForDrag);
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -696,38 +690,27 @@ static int translateKey(unsigned int key)
|
|||||||
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
NSPasteboard* pasteboard = [sender draggingPasteboard];
|
||||||
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
|
NSArray* files = [pasteboard propertyListForType:NSFilenamesPboardType];
|
||||||
|
|
||||||
// set the first char to 0 so strcat
|
|
||||||
// starts to add from the beginning
|
|
||||||
fileNamesForDrag[0] = 0;
|
|
||||||
|
|
||||||
const int dragX = [sender draggingLocation].x;
|
|
||||||
const int dragY = [sender draggingLocation].y;
|
|
||||||
int dragSize = 1;
|
|
||||||
|
|
||||||
if ([files count])
|
|
||||||
{
|
|
||||||
NSEnumerator* filenameEnum = [files objectEnumerator];
|
|
||||||
NSString* name;
|
|
||||||
|
|
||||||
while (name = [filenameEnum nextObject])
|
|
||||||
{
|
|
||||||
dragSize += [name length] + 1;
|
|
||||||
|
|
||||||
if (dragSize > fileNamesSize)
|
|
||||||
{
|
|
||||||
fileNamesSize *= 2;
|
|
||||||
fileNamesForDrag = realloc(fileNamesForDrag, fileNamesSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat(fileNamesForDrag, [name UTF8String]);
|
|
||||||
strcat(fileNamesForDrag, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int height;
|
int height;
|
||||||
_glfwPlatformGetWindowSize(window, NULL, &height);
|
_glfwPlatformGetWindowSize(window, NULL, &height);
|
||||||
_glfwInputCursorMotion(window, dragX, height - dragY);
|
_glfwInputCursorMotion(window,
|
||||||
_glfwInputDrop(window, fileNamesForDrag);
|
[sender draggingLocation].x,
|
||||||
|
height - [sender draggingLocation].y);
|
||||||
|
|
||||||
|
const int count = [files count];
|
||||||
|
if (count)
|
||||||
|
{
|
||||||
|
NSEnumerator* e = [files objectEnumerator];
|
||||||
|
char** names = calloc(count, sizeof(char*));
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
names[i] = strdup([[e nextObject] UTF8String]);
|
||||||
|
|
||||||
|
_glfwInputDrop(window, count, (const char**) names);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
free(names[i]);
|
||||||
|
free(names);
|
||||||
|
}
|
||||||
|
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
@ -211,10 +211,10 @@ void _glfwInputCursorEnter(_GLFWwindow* window, int entered)
|
|||||||
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
|
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _glfwInputDrop(_GLFWwindow* window, const char* dropString)
|
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names)
|
||||||
{
|
{
|
||||||
if (window->callbacks.drop)
|
if (window->callbacks.drop)
|
||||||
window->callbacks.drop((GLFWwindow*) window, dropString);
|
window->callbacks.drop((GLFWwindow*) window, count, names);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -681,11 +681,11 @@ void _glfwInputError(int error, const char* format, ...);
|
|||||||
|
|
||||||
/*! @brief Notifies dropped object over window.
|
/*! @brief Notifies dropped object over window.
|
||||||
* @param[in] window The window that received the event.
|
* @param[in] window The window that received the event.
|
||||||
* @param[in] dropString The string descriptor of the dropped object
|
* @param[in] count The number of dropped objects.
|
||||||
* description.
|
* @param[in] names The names of the dropped objects.
|
||||||
* @ingroup event
|
* @ingroup event
|
||||||
*/
|
*/
|
||||||
void _glfwInputDrop(_GLFWwindow* window, const char* dropString);
|
void _glfwInputDrop(_GLFWwindow* window, int count, const char** names);
|
||||||
|
|
||||||
|
|
||||||
//========================================================================
|
//========================================================================
|
||||||
|
@ -215,9 +215,6 @@ int _glfwPlatformInit(void)
|
|||||||
if (!_glfwInitContextAPI())
|
if (!_glfwInitContextAPI())
|
||||||
return GL_FALSE;
|
return GL_FALSE;
|
||||||
|
|
||||||
_glfw.win32.dropString = malloc(1000);
|
|
||||||
_glfw.win32.dropStringSize = 1000;
|
|
||||||
|
|
||||||
_glfwInitTimer();
|
_glfwInitTimer();
|
||||||
_glfwInitJoysticks();
|
_glfwInitJoysticks();
|
||||||
|
|
||||||
|
@ -169,8 +169,6 @@ typedef struct _GLFWlibraryWin32
|
|||||||
ATOM classAtom;
|
ATOM classAtom;
|
||||||
DWORD foregroundLockTimeout;
|
DWORD foregroundLockTimeout;
|
||||||
char* clipboardString;
|
char* clipboardString;
|
||||||
char* dropString;
|
|
||||||
int dropStringSize;
|
|
||||||
|
|
||||||
// Timer data
|
// Timer data
|
||||||
struct {
|
struct {
|
||||||
|
@ -751,38 +751,34 @@ static LRESULT CALLBACK windowProc(HWND hWnd, UINT uMsg,
|
|||||||
|
|
||||||
case WM_DROPFILES:
|
case WM_DROPFILES:
|
||||||
{
|
{
|
||||||
WCHAR szName[MAX_PATH];
|
|
||||||
HDROP hDrop = (HDROP) wParam;
|
HDROP hDrop = (HDROP) wParam;
|
||||||
POINT pt;
|
POINT pt;
|
||||||
const int numFiles = DragQueryFile(hDrop, 0xffffffff, szName, MAX_PATH);
|
int i;
|
||||||
int i, currentSize = 1;
|
|
||||||
char* utf8str;
|
const int count = DragQueryFile(hDrop, 0xffffffff, NULL, 0);
|
||||||
|
char** names = calloc(count, sizeof(char*));
|
||||||
|
|
||||||
// Move the mouse to the position of the drop
|
// Move the mouse to the position of the drop
|
||||||
DragQueryPoint(hDrop, &pt);
|
DragQueryPoint(hDrop, &pt);
|
||||||
_glfwInputCursorMotion(window, pt.x, pt.y);
|
_glfwInputCursorMotion(window, pt.x, pt.y);
|
||||||
|
|
||||||
memset(_glfw.win32.dropString, 0, _glfw.win32.dropStringSize);
|
for (i = 0; i < count; i++)
|
||||||
|
|
||||||
for (i = 0; i < numFiles; i++)
|
|
||||||
{
|
{
|
||||||
DragQueryFile(hDrop, i, szName, MAX_PATH);
|
const UINT length = DragQueryFile(hDrop, i, NULL, 0);
|
||||||
utf8str = _glfwCreateUTF8FromWideString((const WCHAR*) szName);
|
WCHAR* buffer = calloc(length + 1, sizeof(WCHAR));
|
||||||
currentSize += strlen(utf8str);
|
|
||||||
|
|
||||||
if (_glfw.win32.dropStringSize < currentSize)
|
DragQueryFile(hDrop, i, buffer, length + 1);
|
||||||
{
|
names[i] = _glfwCreateUTF8FromWideString(buffer);
|
||||||
_glfw.win32.dropStringSize *= 2;
|
|
||||||
_glfw.win32.dropString = realloc(_glfw.win32.dropString,
|
|
||||||
_glfw.win32.dropStringSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
strcat(_glfw.win32.dropString, utf8str);
|
free(buffer);
|
||||||
strcat(_glfw.win32.dropString, "\n");
|
|
||||||
free(utf8str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_glfwInputDrop(window,_glfw.win32.dropString);
|
_glfwInputDrop(window, count, (const char**) names);
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
free(names[i]);
|
||||||
|
free(names);
|
||||||
|
|
||||||
DragFinish(hDrop);
|
DragFinish(hDrop);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -132,10 +132,6 @@ typedef struct _GLFWlibraryX11
|
|||||||
|
|
||||||
struct {
|
struct {
|
||||||
Window sourceWindow;
|
Window sourceWindow;
|
||||||
char* string;
|
|
||||||
char* type1;
|
|
||||||
char* type2;
|
|
||||||
char* type3;
|
|
||||||
} xdnd;
|
} xdnd;
|
||||||
|
|
||||||
// Selection atoms
|
// Selection atoms
|
||||||
|
@ -97,6 +97,51 @@ static int translateChar(XKeyEvent* event)
|
|||||||
return (int) _glfwKeySym2Unicode(keysym);
|
return (int) _glfwKeySym2Unicode(keysym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Splits a text/uri-list into separate file paths
|
||||||
|
//
|
||||||
|
static char** splitUriList(char* text, int* count)
|
||||||
|
{
|
||||||
|
const char* prefix = "file://";
|
||||||
|
char** names = NULL;
|
||||||
|
char* line;
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
|
||||||
|
while ((line = strtok(text, "\r\n")))
|
||||||
|
{
|
||||||
|
text = NULL;
|
||||||
|
|
||||||
|
if (*line == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(line, prefix, strlen(prefix)) == 0)
|
||||||
|
line += strlen(prefix);
|
||||||
|
|
||||||
|
(*count)++;
|
||||||
|
|
||||||
|
char* name = calloc(strlen(line) + 1, 1);
|
||||||
|
names = realloc(names, *count * sizeof(char*));
|
||||||
|
names[*count - 1] = name;
|
||||||
|
|
||||||
|
while (*line)
|
||||||
|
{
|
||||||
|
if (line[0] == '%' && line[1] && line[2])
|
||||||
|
{
|
||||||
|
const char digits[3] = { line[1], line[2], '\0' };
|
||||||
|
*name = strtol(digits, NULL, 16);
|
||||||
|
line += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*name = *line;
|
||||||
|
|
||||||
|
name++;
|
||||||
|
line++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
// Create the X11 window (and its colormap)
|
// Create the X11 window (and its colormap)
|
||||||
//
|
//
|
||||||
static GLboolean createWindow(_GLFWwindow* window,
|
static GLboolean createWindow(_GLFWwindow* window,
|
||||||
@ -714,7 +759,6 @@ static void processEvent(XEvent *event)
|
|||||||
False,
|
False,
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask,
|
SubstructureNotifyMask | SubstructureRedirectMask,
|
||||||
event);
|
event);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (event->xclient.message_type == _glfw.x11.XdndEnter)
|
else if (event->xclient.message_type == _glfw.x11.XdndEnter)
|
||||||
{
|
{
|
||||||
@ -733,9 +777,6 @@ static void processEvent(XEvent *event)
|
|||||||
_glfw.x11.XdndSelection,
|
_glfw.x11.XdndSelection,
|
||||||
window->x11.handle, CurrentTime);
|
window->x11.handle, CurrentTime);
|
||||||
}
|
}
|
||||||
else if (event->xclient.message_type == _glfw.x11.XdndLeave)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else if (event->xclient.message_type == _glfw.x11.XdndPosition)
|
else if (event->xclient.message_type == _glfw.x11.XdndPosition)
|
||||||
{
|
{
|
||||||
// Xdnd Position: get coordinates of the mouse inside the window
|
// Xdnd Position: get coordinates of the mouse inside the window
|
||||||
@ -771,15 +812,12 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
case SelectionNotify:
|
case SelectionNotify:
|
||||||
{
|
{
|
||||||
if (event->xselection.property != None)
|
if (event->xselection.property)
|
||||||
{
|
{
|
||||||
// Xdnd: got a selection notification from the conversion
|
// Xdnd: got a selection notification from the conversion
|
||||||
// we asked for, get the data and finish the d&d event
|
// we asked for, get the data and finish the d&d event
|
||||||
char* data;
|
char* data;
|
||||||
|
|
||||||
free(_glfw.x11.xdnd.string);
|
|
||||||
_glfw.x11.xdnd.string = NULL;
|
|
||||||
|
|
||||||
const int result = _glfwGetWindowProperty(event->xselection.requestor,
|
const int result = _glfwGetWindowProperty(event->xselection.requestor,
|
||||||
event->xselection.property,
|
event->xselection.property,
|
||||||
event->xselection.target,
|
event->xselection.target,
|
||||||
@ -787,30 +825,18 @@ static void processEvent(XEvent *event)
|
|||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
// Nautilus seems to add a \r at the end of the paths
|
int i, count;
|
||||||
// remove it so paths can be directly used
|
char** names = splitUriList(data, &count);
|
||||||
_glfw.x11.xdnd.string = malloc(strlen(data) + 1);
|
|
||||||
char *to = _glfw.x11.xdnd.string;
|
|
||||||
const char *from = data;
|
|
||||||
const char *current = strchr(from, '\r');
|
|
||||||
|
|
||||||
while (current)
|
_glfwInputDrop(window, count, (const char**) names);
|
||||||
{
|
|
||||||
const int charsToCopy = current - from;
|
|
||||||
memcpy(to, from, (size_t) charsToCopy);
|
|
||||||
to += charsToCopy;
|
|
||||||
|
|
||||||
from = current + 1;
|
for (i = 0; i < count; i++)
|
||||||
current = strchr(from, '\r');
|
free(names[i]);
|
||||||
}
|
free(names);
|
||||||
|
|
||||||
const size_t remaining = strlen(from);
|
|
||||||
|
|
||||||
memcpy(to, from, remaining);
|
|
||||||
to += remaining;
|
|
||||||
*to = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
XFree(data);
|
||||||
|
|
||||||
XEvent reply;
|
XEvent reply;
|
||||||
memset(&reply, 0, sizeof(reply));
|
memset(&reply, 0, sizeof(reply));
|
||||||
|
|
||||||
@ -825,11 +851,7 @@ static void processEvent(XEvent *event)
|
|||||||
// Reply that all is well
|
// Reply that all is well
|
||||||
XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.sourceWindow,
|
XSendEvent(_glfw.x11.display, _glfw.x11.xdnd.sourceWindow,
|
||||||
False, NoEventMask, &reply);
|
False, NoEventMask, &reply);
|
||||||
XSync(_glfw.x11.display, False);
|
XFlush(_glfw.x11.display);
|
||||||
XFree(data);
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
_glfwInputDrop(window, _glfw.x11.xdnd.string);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -381,12 +381,14 @@ static void char_callback(GLFWwindow* window, unsigned int codepoint)
|
|||||||
get_character_string(codepoint));
|
get_character_string(codepoint));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void drop_callback(GLFWwindow* window, const char* descriptor)
|
static void drop_callback(GLFWwindow* window, int count, const char** names)
|
||||||
{
|
{
|
||||||
printf("%08x at %0.3f: Drop of \"%s\" input\n",
|
int i;
|
||||||
counter++,
|
|
||||||
glfwGetTime(),
|
printf("%08x at %0.3f: Drop input\n", counter++, glfwGetTime());
|
||||||
descriptor);
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
printf(" %i: \"%s\"\n", i, names[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void monitor_callback(GLFWmonitor* monitor, int event)
|
void monitor_callback(GLFWmonitor* monitor, int event)
|
||||||
|
Loading…
Reference in New Issue
Block a user