Skip to content

Commit 545b7ab

Browse files
committed
fix(macos): use modern pasteboard API for drag-drop file collection
Switch `collect_paths` to `NSPasteboard.readObjectsForClasses:options:` with `NSURL`, which covers both legacy `NSFilenamesPboardType` and the modern per-item `public.file-url` type (the standard for sources using `NSDraggingItem.initWithPasteboardWriter:` with `NSPasteboardItem`). This also removes the panic when the source publishes only the modern type: `availableTypeFromArray:` reported the legacy type was derivable but `propertyListForType:` returned nil, hitting an `unwrap` and crashing the webview process. The new code has no `unwrap` calls — failures skip the entry. The legacy `NSFilenamesPboardType` branch is kept as a defensive fallback.
1 parent 9d0a9fe commit 545b7ab

2 files changed

Lines changed: 45 additions & 9 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"wry": patch
3+
---
4+
5+
On macOS, use the modern `readObjectsForClasses:options:` pasteboard API to collect dragged file paths. This fixes a panic when the drag source publishes only the modern per-item `public.file-url` type (as `NSDraggingItem.initWithPasteboardWriter:` does) instead of the legacy `NSFilenamesPboardType`, and removes the deprecated API as the primary path. The legacy type is kept as a defensive fallback.

src/wkwebview/drag_drop.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,58 @@ use std::{ffi::CStr, path::PathBuf};
66

77
use objc2::{
88
runtime::{Bool, ProtocolObject},
9-
DeclaredClass,
9+
ClassType, DeclaredClass,
1010
};
1111
use objc2_app_kit::{NSDragOperation, NSDraggingInfo, NSFilenamesPboardType};
12-
use objc2_foundation::{NSArray, NSPoint, NSRect, NSString};
12+
use objc2_foundation::{NSArray, NSPoint, NSRect, NSString, NSURL};
1313

1414
use crate::DragDropEvent;
1515

1616
use super::WryWebView;
1717

1818
pub(crate) unsafe fn collect_paths(drag_info: &ProtocolObject<dyn NSDraggingInfo>) -> Vec<PathBuf> {
19+
// Prefer the modern `readObjectsForClasses:options:` API with `NSURL`. It works
20+
// for sources that publish per-item `public.file-url` types (the standard for
21+
// `NSDraggingItem.initWithPasteboardWriter:` with `NSPasteboardItem`) as well
22+
// as the legacy `NSFilenamesPboardType` payload, so it covers both paths in
23+
// one call.
24+
//
25+
// The legacy `NSFilenamesPboardType` branch below is kept as a defensive
26+
// fallback in case `readObjectsForClasses:options:` returns nothing on some
27+
// configuration; it should not normally be reached.
28+
//
29+
// No `unwrap` calls: every conversion that can fail skips the entry, so a
30+
// malformed pasteboard never panics the webview process.
1931
let pb = drag_info.draggingPasteboard();
2032
let mut drag_drop_paths = Vec::new();
21-
let types = NSArray::arrayWithObject(NSFilenamesPboardType);
2233

34+
let url_classes = NSArray::from_slice(&[NSURL::class()]);
35+
if let Some(items) = pb.readObjectsForClasses_options(&url_classes, None) {
36+
for item in &items {
37+
if let Some(url) = item.downcast_ref::<NSURL>() {
38+
if let Some(path) = url.path() {
39+
let path = CStr::from_ptr(path.UTF8String()).to_string_lossy();
40+
drag_drop_paths.push(PathBuf::from(path.into_owned()));
41+
}
42+
}
43+
}
44+
if !drag_drop_paths.is_empty() {
45+
return drag_drop_paths;
46+
}
47+
}
48+
49+
// Legacy fallback: read `NSFilenamesPboardType` directly.
50+
let types = NSArray::arrayWithObject(NSFilenamesPboardType);
2351
if pb.availableTypeFromArray(&types).is_some() {
24-
let paths = pb.propertyListForType(NSFilenamesPboardType).unwrap();
25-
let paths = paths.downcast::<NSArray>().unwrap();
26-
for path in paths {
27-
let path = path.downcast::<NSString>().unwrap();
28-
let path = CStr::from_ptr(path.UTF8String()).to_string_lossy();
29-
drag_drop_paths.push(PathBuf::from(path.into_owned()));
52+
if let Some(paths) = pb.propertyListForType(NSFilenamesPboardType) {
53+
if let Ok(paths) = paths.downcast::<NSArray>() {
54+
for path in paths {
55+
if let Ok(path) = path.downcast::<NSString>() {
56+
let path = CStr::from_ptr(path.UTF8String()).to_string_lossy();
57+
drag_drop_paths.push(PathBuf::from(path.into_owned()));
58+
}
59+
}
60+
}
3061
}
3162
}
3263
drag_drop_paths

0 commit comments

Comments
 (0)