Cleaned up drop callback design.

This commit is contained in:
Camilla Berglund 2013-12-22 19:28:46 +01:00
parent ed4c8b27f1
commit 8f349e84ae
11 changed files with 106 additions and 110 deletions

View File

@ -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

View File

@ -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.
* *

View File

@ -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;
} }

View File

@ -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);
} }

View File

@ -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);
//======================================================================== //========================================================================

View File

@ -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();

View File

@ -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 {

View File

@ -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;
} }

View File

@ -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

View File

@ -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;

View File

@ -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)