Fix circular locking in prompts

Sometimes Cocoa calls app delegate methods (notably the display link)
while we're calling Cocoa methods. This causes a deadlock unless we
are careful to run cocao methods while we're not holding our internal
locks
This commit is contained in:
Conrad Irwin 2024-01-24 19:40:01 -07:00
parent 6ed7cc7833
commit 249a6da54a

View file

@ -534,67 +534,77 @@ impl Platform for MacPlatform {
&self, &self,
options: PathPromptOptions, options: PathPromptOptions,
) -> oneshot::Receiver<Option<Vec<PathBuf>>> { ) -> oneshot::Receiver<Option<Vec<PathBuf>>> {
unsafe { let (done_tx, done_rx) = oneshot::channel();
let panel = NSOpenPanel::openPanel(nil); self.foreground_executor()
panel.setCanChooseDirectories_(options.directories.to_objc()); .spawn(async move {
panel.setCanChooseFiles_(options.files.to_objc()); unsafe {
panel.setAllowsMultipleSelection_(options.multiple.to_objc()); let panel = NSOpenPanel::openPanel(nil);
panel.setResolvesAliases_(false.to_objc()); panel.setCanChooseDirectories_(options.directories.to_objc());
let (done_tx, done_rx) = oneshot::channel(); panel.setCanChooseFiles_(options.files.to_objc());
let done_tx = Cell::new(Some(done_tx)); panel.setAllowsMultipleSelection_(options.multiple.to_objc());
let block = ConcreteBlock::new(move |response: NSModalResponse| { panel.setResolvesAliases_(false.to_objc());
let result = if response == NSModalResponse::NSModalResponseOk { let done_tx = Cell::new(Some(done_tx));
let mut result = Vec::new(); let block = ConcreteBlock::new(move |response: NSModalResponse| {
let urls = panel.URLs(); let result = if response == NSModalResponse::NSModalResponseOk {
for i in 0..urls.count() { let mut result = Vec::new();
let url = urls.objectAtIndex(i); let urls = panel.URLs();
if url.isFileURL() == YES { for i in 0..urls.count() {
if let Ok(path) = ns_url_to_path(url) { let url = urls.objectAtIndex(i);
result.push(path) if url.isFileURL() == YES {
if let Ok(path) = ns_url_to_path(url) {
result.push(path)
}
}
} }
} Some(result)
} } else {
Some(result) None
} else { };
None
};
if let Some(done_tx) = done_tx.take() { if let Some(done_tx) = done_tx.take() {
let _ = done_tx.send(result); let _ = done_tx.send(result);
}
});
let block = block.copy();
let _: () = msg_send![panel, beginWithCompletionHandler: block];
} }
}); })
let block = block.copy(); .detach();
let _: () = msg_send![panel, beginWithCompletionHandler: block]; done_rx
done_rx
}
} }
fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> { fn prompt_for_new_path(&self, directory: &Path) -> oneshot::Receiver<Option<PathBuf>> {
unsafe { let directory = directory.to_owned();
let panel = NSSavePanel::savePanel(nil); let (done_tx, done_rx) = oneshot::channel();
let path = ns_string(directory.to_string_lossy().as_ref()); self.foreground_executor()
let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc()); .spawn(async move {
panel.setDirectoryURL(url); unsafe {
let panel = NSSavePanel::savePanel(nil);
let path = ns_string(directory.to_string_lossy().as_ref());
let url = NSURL::fileURLWithPath_isDirectory_(nil, path, true.to_objc());
panel.setDirectoryURL(url);
let (done_tx, done_rx) = oneshot::channel(); let done_tx = Cell::new(Some(done_tx));
let done_tx = Cell::new(Some(done_tx)); let block = ConcreteBlock::new(move |response: NSModalResponse| {
let block = ConcreteBlock::new(move |response: NSModalResponse| { let mut result = None;
let mut result = None; if response == NSModalResponse::NSModalResponseOk {
if response == NSModalResponse::NSModalResponseOk { let url = panel.URL();
let url = panel.URL(); if url.isFileURL() == YES {
if url.isFileURL() == YES { result = ns_url_to_path(panel.URL()).ok()
result = ns_url_to_path(panel.URL()).ok() }
} }
}
if let Some(done_tx) = done_tx.take() { if let Some(done_tx) = done_tx.take() {
let _ = done_tx.send(result); let _ = done_tx.send(result);
}
});
let block = block.copy();
let _: () = msg_send![panel, beginWithCompletionHandler: block];
} }
}); })
let block = block.copy(); .detach();
let _: () = msg_send![panel, beginWithCompletionHandler: block];
done_rx done_rx
}
} }
fn reveal_path(&self, path: &Path) { fn reveal_path(&self, path: &Path) {