Multiple drag and drop issue and fix on mac


#1

performExternalDragDropOfFiles, in juce_mac_Windowing.mm, has an issue when dragging multiple files from a JUCE window into, say, the finder. Only the first file in the list was dropped.

In the article found here: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/DragandDrop/Tasks/DraggingFiles.html#//apple_ref/doc/uid/20001288-101271 in the “Dragging File Paths” section, it is stated as below:

“To initiate a drag operation on multiple files, you need to use the NSView or NSWindow method dragImage:at:offset:event:pasteboard:source:slideBack:. You must place the array of file paths onto the pasteboard yourself, using the NSPasteboard method setPropertyList:forType: …”

So I changed the function source from:

bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /canMoveFiles/)
{
if (files.size() == 0)
return false;

MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
if (draggingSource == nullptr)
{
    jassertfalse;  // This method must be called in response to a component's mouseDown or mouseDrag event!
    return false;
}
Component* sourceComp = draggingSource->getComponentUnderMouse();
if (sourceComp == nullptr)
{
    jassertfalse;  // This method must be called in response to a component's mouseDown or mouseDrag event!
    return false;
}
JUCE_AUTORELEASEPOOL
{
    if (NSView* view = (NSView*) sourceComp->getWindowHandle())
    {
        if (NSEvent* event = [[view window] currentEvent])
        {
            NSPoint eventPos = [event locationInWindow];
            NSRect dragRect = [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
                                       fromView: nil];
            for (int i = 0; i < files.size(); ++i)
            {
                if (! [view dragFile: juceStringToNS (files[i])
                            fromRect: dragRect
                           slideBack: YES
                               event: event])
                    return false;
            }
            return true;
        }
    }
}
return false;

}

to:

bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool /canMoveFiles/)
{
if (files.size() == 0)
return false;

MouseInputSource* draggingSource = Desktop::getInstance().getDraggingMouseSource(0);
if (draggingSource == nullptr)
{
    jassertfalse;  // This method must be called in response to a component's mouseDown or mouseDrag event!
    return false;
}
Component* sourceComp = draggingSource->getComponentUnderMouse();
if (sourceComp == nullptr)
{
    jassertfalse;  // This method must be called in response to a component's mouseDown or mouseDrag event!
    return false;
}
JUCE_AUTORELEASEPOOL
{
    if (NSView* view = (NSView*) sourceComp->getWindowHandle())
    {
        if (NSEvent* event = [[view window] currentEvent])
        {
            NSPoint eventPos = [event locationInWindow];
            NSRect dragRect = [view convertRect: NSMakeRect (eventPos.x - 16.0f, eventPos.y - 16.0f, 32.0f, 32.0f)
                                       fromView: nil];
            if (files.size() == 1){
                if (! [view dragFile: juceStringToNS (files[0])
                            fromRect: dragRect
                           slideBack: YES
                               event: event])
                    return false;
            }
            else
            {
                NSMutableArray *fileList = [[NSMutableArray alloc] init];
                for (int i = 0; i < files.size(); ++i){
                    [fileList addObject:juceStringToNS(files[i])];
                }
                // Write data to the pasteboard
                NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
                [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
                               owner:nil];
                [pboard setPropertyList:fileList forType:NSFilenamesPboardType];
                
                // Start the multiple drag operation
                NSImage *dragImage = [[NSWorkspace sharedWorkspace] iconForFile:juceStringToNS(files[0])];
                [view dragImage:dragImage
                             at:eventPos
                         offset:NSZeroSize
                          event:event
                     pasteboard:pboard
                         source:view
                      slideBack:YES];
            }
            return true;
        }
    }
}
return false;

}

Now all files are copied to the destination, in finder, or in a DAW when dragging mp3 or wav files.
I’m hoping this will solve the issue for anyone who encountered the same problem.
Cheers,
Jacques


#2

Yep - I’ve just encountered this problem. I’ll try the fix. Maybe someone from the JUCE team would like to look at it :slight_smile:


#3

I’ve just pushed a fix for this.


#4

Tom/All - I’ve got two fixes for things now in the develop branch. When do you think they’d be available in the master branch?


#5

Once the new JUCE 5 features on the develop branch have had enough real world testing then they’ll become part of the JUCE 5 release. However, since this fix is an easy cherry pick, I’ll add it to the current master.


#6

I’ve got another request then … there’s a fix Fabian put in for ableton last year:


which it would be also great to see in master, and also looks small… :slight_smile: