@@ -1492,10 +1492,15 @@ - (BOOL)wantsPeriodicDraggingUpdates
14921492 for (NSString *key in window->ns .drop_data .file_promise_mapping ) {
14931493 NSArray *pair = [window->ns.drop_data.file_promise_mapping objectForKey: key];
14941494 error = nil ; if (pair[1 ] != [NSNull null ]) [pair[1 ] closeAndReturnError: &error];
1495- error = nil ; [fileManager removeItemAtURL: pair[0 ] error: &error];
1495+ if (pair[ 0 ] != [ NSNull null ]) { error = nil ; [fileManager removeItemAtURL: pair[0 ] error: &error]; }
14961496 }
14971497 [window->ns.drop_data.file_promise_mapping release ];
14981498 }
1499+ if (window->ns .drop_data .file_promise_temp_dir ) {
1500+ NSError *error = nil ;
1501+ [[NSFileManager defaultManager ] removeItemAtURL: window->ns.drop_data.file_promise_temp_dir error: &error];
1502+ [window->ns.drop_data.file_promise_temp_dir release ];
1503+ }
14991504 memset (&window->ns .drop_data , 0 , sizeof (_GLFWDropData));
15001505}
15011506
@@ -1720,11 +1725,73 @@ - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
17201725 data = [uri_list dataUsingEncoding: NSUTF8StringEncoding];
17211726 } else {
17221727 window->ns .drop_data .file_promise_mapping [@(mime)] = @[[NSNull null ], [NSNull null ], [NSNull null ]];
1723- // TODO: store all file promise based items that conform to UTTypeFileURL into a temp dir
1724- // and once that's complete, generate a response with file:// URLs pointing to the items in that temp dir
1725- // This must be done in the background but remember to send the GLFW_DROP_DATA_AVAILABLE event on main thread.
1726- // The temporary directory must live until the next drop event for this window starts.
1727- // It must also be deleted when the window is destroyed.
1728+ // Create a unique temp directory that lives until the next drop event or window destruction
1729+ NSError *mkdirError = nil ;
1730+ NSString *tmpDirPath = [NSTemporaryDirectory () stringByAppendingPathComponent:
1731+ [[NSUUID UUID ] UUIDString ]];
1732+ NSURL *tmpDirURL = [NSURL fileURLWithPath: tmpDirPath isDirectory: YES ];
1733+ if (![[NSFileManager defaultManager ] createDirectoryAtURL: tmpDirURL
1734+ withIntermediateDirectories: YES attributes: nil error: &mkdirError]) {
1735+ NSLog (@" Failed to create temp dir for file promises: %@ " , mkdirError);
1736+ return 0 ;
1737+ }
1738+ window->ns .drop_data .file_promise_temp_dir = [tmpDirURL retain ];
1739+ // Collect file promise receivers whose UTIs conform to UTTypeFileURL
1740+ NSArray *all_receivers = [pasteboard readObjectsForClasses: @[[NSFilePromiseReceiver class]] options: @{}];
1741+ NSMutableArray *file_receivers = [NSMutableArray array ];
1742+ for (NSFilePromiseReceiver *receiver in all_receivers) {
1743+ for (NSString *ruti in receiver.fileTypes ) {
1744+ UTType *promisedType = [UTType typeWithIdentifier: ruti];
1745+ if (promisedType && [promisedType conformsToType: UTTypeFileURL]) {
1746+ [file_receivers addObject: receiver];
1747+ break ;
1748+ }
1749+ }
1750+ }
1751+ if ([file_receivers count ] == 0 ) {
1752+ // Nothing to receive; emit an empty uri-list immediately
1753+ if (window->ns .drop_data .data_mapping == nil )
1754+ window->ns .drop_data .data_mapping = [[NSMutableDictionary alloc ] init ];
1755+ window->ns .drop_data .data_mapping [@(mime)] = @[[NSData data ], @0 ];
1756+ [window->ns.drop_data.file_promise_mapping removeObjectForKey: @(mime)];
1757+ send_data_available_event_on_next_event_loop_tick (wid, mime);
1758+ return 0 ;
1759+ }
1760+ char *mt = _glfw_strdup (mime);
1761+ NSMutableArray *collected_urls = [[NSMutableArray alloc ] init ];
1762+ dispatch_group_t group = dispatch_group_create ();
1763+ NSOperationQueue *opQueue = [[NSOperationQueue alloc ] init ];
1764+ opQueue.maxConcurrentOperationCount = 1 ; // serial: safe to append to collected_urls
1765+ for (NSFilePromiseReceiver *receiver in file_receivers) {
1766+ dispatch_group_enter (group);
1767+ [receiver receivePromisedFilesAtDestination: tmpDirURL options: @{}
1768+ operationQueue: opQueue
1769+ reader: ^(NSURL *fileURL, NSError *errorOrNil) {
1770+ if (!errorOrNil && fileURL) [collected_urls addObject: fileURL];
1771+ dispatch_group_leave (group);
1772+ }];
1773+ }
1774+ dispatch_group_notify (group, dispatch_get_main_queue (), ^{
1775+ dispatch_release (group);
1776+ _GLFWwindow *w = _glfwWindowForId (wid);
1777+ if (w && w->ns .drop_data .file_promise_mapping ) {
1778+ if (w->ns .drop_data .data_mapping == nil )
1779+ w->ns .drop_data .data_mapping = [[NSMutableDictionary alloc ] init ];
1780+ NSMutableString *uri_list = [NSMutableString stringWithCapacity: 4096 ];
1781+ for (NSURL *url in collected_urls) {
1782+ if ([uri_list length ] > 0 ) [uri_list appendString: @" \n " ];
1783+ [uri_list appendString: url.absoluteString];
1784+ }
1785+ NSData *result = [uri_list dataUsingEncoding: NSUTF8StringEncoding];
1786+ w->ns .drop_data .data_mapping [@(mt)] = @[result, @0 ];
1787+ [w->ns.drop_data.file_promise_mapping removeObjectForKey: @(mt)];
1788+ const char *mimes[1 ] = {mt};
1789+ _glfwInputDropEvent (w, GLFW_DROP_DATA_AVAILABLE , 0 , 0 , mimes, 1 , false );
1790+ }
1791+ [collected_urls release ];
1792+ [opQueue release ];
1793+ free (mt);
1794+ });
17281795 return 0 ;
17291796 }
17301797 } else if (strcmp (mime, " text/plain" ) == 0 || strcmp (mime, " text/plain;charset=utf-8" ) == 0 ) {
0 commit comments