diff --git a/src/cocoa_window.m b/src/cocoa_window.m index 6209d1eb..3925b107 100644 --- a/src/cocoa_window.m +++ b/src/cocoa_window.m @@ -390,6 +390,8 @@ static int translateKey(unsigned int key) @interface GLFWContentView : NSView { _GLFWwindow* window; + char * fileNamesForDrag; + int fileNamesSize; NSTrackingArea* trackingArea; } @@ -420,8 +422,15 @@ static int translateKey(unsigned int key) { window = initWindow; trackingArea = nil; - + + fileNamesForDrag = (char*)malloc(1024); + fileNamesSize = 1024; + [self updateTrackingAreas]; + + + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSFilenamesPboardType, nil]]; } return self; @@ -430,6 +439,7 @@ static int translateKey(unsigned int key) -(void)dealloc { [trackingArea release]; + free(fileNamesForDrag); [super dealloc]; } @@ -613,10 +623,70 @@ static int translateKey(unsigned int key) _glfwInputScroll(window, deltaX, deltaY); } -- (void)resetCursorRects + +// arturoc: this makes the cursor dissapear when the window is +// resized or received a drag operation +/*- (void)resetCursorRects { [self discardCursorRects]; [self addCursorRect:[self bounds] cursor:_glfw.ns.cursor]; +}*/ + +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) { + + [self setNeedsDisplay:YES]; + + return NSDragOperationGeneric; + + } + + return NSDragOperationNone; +} + +- (BOOL)prepareForDragOperation:(id )sender { + [self setNeedsDisplay:YES]; + return YES; +} + +- (BOOL)performDragOperation:(id )sender { + NSPasteboard *zPasteboard = [sender draggingPasteboard]; + NSArray *files = [zPasteboard propertyListForType:NSFilenamesPboardType]; + + // set the first char to 0 so strcat + // starts to add from the beginning + fileNamesForDrag[0] = 0; + + int dragX = [sender draggingLocation].x; + 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; + _glfwPlatformGetWindowSize(window, NULL, &height); + _glfwInputCursorMotion(window, dragX, height-dragY); + _glfwInputDrop(window, fileNamesForDrag); + + return YES; +} + +- (void)concludeDragOperation:(id )sender { + [self setNeedsDisplay:YES]; } @end diff --git a/src/x11_init.c b/src/x11_init.c index eed9f5a2..cd3f5bfd 100644 --- a/src/x11_init.c +++ b/src/x11_init.c @@ -546,14 +546,11 @@ static GLboolean 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.XdndTypeList = XInternAtom(_glfw.x11.display, "XdndTypeList", False); _glfw.x11.XdndActionCopy = XInternAtom(_glfw.x11.display, "XdndActionCopy", False); _glfw.x11.XdndDrop = XInternAtom(_glfw.x11.display, "XdndDrop", False); _glfw.x11.XdndLeave = XInternAtom(_glfw.x11.display, "XdndLeave", False); _glfw.x11.XdndFinished = XInternAtom(_glfw.x11.display, "XdndFinished", False); _glfw.x11.XdndSelection = XInternAtom(_glfw.x11.display, "XdndSelection", False); - _glfw.x11.XdndProxy = XInternAtom(_glfw.x11.display, "XdndProxy", False); - _glfw.x11.XA_TARGETS = XInternAtom(_glfw.x11.display, "TARGETS", False); _glfw.x11.xdnd.string = NULL; _glfw.x11.xdnd.type1 = NULL; _glfw.x11.xdnd.type2 = NULL; diff --git a/src/x11_platform.h b/src/x11_platform.h index 71a0febc..70a9d5d1 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -127,14 +127,11 @@ typedef struct _GLFWlibraryX11 Atom XdndEnter; Atom XdndPosition; Atom XdndStatus; - Atom XdndTypeList; Atom XdndActionCopy; Atom XdndDrop; Atom XdndLeave; Atom XdndFinished; Atom XdndSelection; - Atom XdndProxy; - Atom XA_TARGETS; struct{ Window sourceWindow; char* string; diff --git a/src/x11_window.c b/src/x11_window.c index 73cc8609..4e30476e 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -714,20 +714,11 @@ static void processEvent(XEvent *event) // the window, ask to convert the selection _glfw.x11.xdnd.sourceWindow = event->xclient.data.l[0]; - - const Atom formats[] = { _glfw.x11.UTF8_STRING, - _glfw.x11.COMPOUND_STRING, - XA_STRING }; - const int formatCount = sizeof(formats) / sizeof(formats[0]); - int i; - - for(i=0;ix11.handle, CurrentTime); - } + XConvertSelection(_glfw.x11.display, + _glfw.x11.XdndSelection, + _glfw.x11.UTF8_STRING, + _glfw.x11.XdndSelection, + window->x11.handle, CurrentTime); } else if(event->xclient.message_type == _glfw.x11.XdndLeave) @@ -740,12 +731,14 @@ static void processEvent(XEvent *event) // and update the mouse position int absX = (event->xclient.data.l[2]>>16) & 0xFFFF; int absY = (event->xclient.data.l[2]) & 0xFFFF; - int x; - int y; - _glfwPlatformGetWindowPos(window,&x,&y); + Window child; + int x, y; - _glfwInputCursorMotion(window,absX-x,absY-y); + XTranslateCoordinates(_glfw.x11.display, _glfw.x11.root, window->x11.handle, + absX, absY, &x, &y, &child); + + _glfwInputCursorMotion(window,x,y); // Xdnd: reply with an XDND status message XClientMessageEvent m; @@ -763,7 +756,6 @@ static void processEvent(XEvent *event) XSendEvent(_glfw.x11.display, event->xclient.data.l[0], False, NoEventMask, (XEvent*)&m); XFlush(_glfw.x11.display); - } break; @@ -776,13 +768,36 @@ static void processEvent(XEvent *event) // Xdnd: got a selection notification from the conversion // we asked for, get the data and finish the d&d event char* data; - _glfwGetWindowProperty(event->xselection.requestor, + free(_glfw.x11.xdnd.string); + _glfw.x11.xdnd.string = NULL; + int result = _glfwGetWindowProperty(event->xselection.requestor, event->xselection.property, event->xselection.target, (unsigned char**) &data); - free(_glfw.x11.xdnd.string); - _glfw.x11.xdnd.string = strdup(data); + if(result){ + // nautilus seems to add a \r at the end of the paths + // remove it so paths can be directly used + _glfw.x11.xdnd.string = malloc(strlen(data)); + char *to = _glfw.x11.xdnd.string; + const char *from = data; + const char *current = strchr(from, '\r'); + while(current) + { + int charsToCopy = current - from; + memcpy(to, from, (size_t)charsToCopy); + to += charsToCopy; + + from = current+1; + current = strchr(from, '\r'); + } + + size_t remaining = strlen(from); + + memcpy(to, from, remaining); + to += remaining; + *to = 0; + } XClientMessageEvent m; memset(&m, sizeof(m), 0); @@ -792,7 +807,7 @@ static void processEvent(XEvent *event) m.message_type = _glfw.x11.XdndFinished; m.format=32; m.data.l[0] = window->x11.handle; - m.data.l[1] = 1; + m.data.l[1] = result; m.data.l[2] = _glfw.x11.XdndActionCopy; //We only ever copy. // Reply that all is well. @@ -802,7 +817,7 @@ static void processEvent(XEvent *event) XFree(data); - _glfwInputDrop(window,_glfw.x11.xdnd.string); + if(result) _glfwInputDrop(window,_glfw.x11.xdnd.string); } break; } @@ -1093,14 +1108,21 @@ void _glfwPlatformGetWindowPos(_GLFWwindow* window, int* xpos, int* ypos) { Window child; int x, y; + int left; + int top; - XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, + + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, _glfw.x11.root, 0, 0, &x, &y, &child); + XTranslateCoordinates(_glfw.x11.display, window->x11.handle, child, + 0, 0, &left, &top, &child); + + if (xpos) *xpos = x; if (ypos) - *ypos = y; + *ypos = y-top; } void _glfwPlatformSetWindowPos(_GLFWwindow* window, int xpos, int ypos)