Wayland / X11 drag files support#119949
Conversation
Initial commit of drag_files method with implemented in x11
Auto formatting on dnd drag changes
Window.drag_files() fix non-named argument
… 50dndgodot2os
window_drag_files documentation added
|
I think there is still a lack of a precise drag-and-drop file feature. Currently, dragging files in is at the entire window level. It would be great if we could set it so that only specific areas (specific UI controls) accept files. Additionally, the ability to drag files out of Godot could also be added to UI controls, which would make things much more convenient. |
|
A quick implementation of the same method for macOS: Patchdiff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index d3fb28f3eb..dc5991d8e0 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -374,8 +374,12 @@ - (BOOL)performDragOperation:(id<NSDraggingInfo>)sender {
return NO;
}
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
+ return NSDragOperationCopy;
+}
+
// MARK: Focus
- (BOOL)canBecomeKeyView {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index f6b9e0327b..cf73aa7a3e 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -393,8 +393,10 @@ public:
virtual void window_start_drag(DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) override;
virtual void window_start_resize(DisplayServerEnums::WindowResizeEdge p_edge, DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) override;
+ virtual void window_drag_files(const PackedStringArray &p_files, DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) override;
+
virtual void window_set_window_buttons_offset(const Vector2i &p_offset, DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) override;
virtual Vector3i window_get_safe_title_margins(DisplayServerEnums::WindowID p_window = DisplayServerEnums::MAIN_WINDOW_ID) const override;
void cursor_update_shape();
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 003c7cc45b..7d4cb88770 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -2358,8 +2358,33 @@
NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeLeftMouseDown location:((NSWindow *)wd.window_object).mouseLocationOutsideOfEventStream modifierFlags:0 timestamp:[[NSProcessInfo processInfo] systemUptime] windowNumber:((NSWindow *)wd.window_object).windowNumber context:nil eventNumber:0 clickCount:1 pressure:1.0f];
[wd.window_object performWindowDragWithEvent:event];
}
+void DisplayServerMacOS::window_drag_files(const PackedStringArray &p_files, DisplayServerEnums::WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(p_files.is_empty());
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ NSPoint local_pos = [wd.window_object convertPointFromScreen:[NSEvent mouseLocation]];
+ NSEvent *event = [NSEvent mouseEventWithType:NSEventTypeLeftMouseDragged location:local_pos modifierFlags:0 timestamp:0 windowNumber:[wd.window_object windowNumber] context:nil eventNumber:0 clickCount:0 pressure:0];
+
+ NSMutableArray *files = [NSMutableArray array];
+ for (const String &file : p_files) {
+ NSString *file_path = [NSString stringWithUTF8String:file.utf8().get_data()];
+ NSURL *file_url = [NSURL fileURLWithPath:file_path];
+ NSImage *file_icon = [[NSWorkspace sharedWorkspace] iconForFile:file_path];
+ NSDraggingItem *drag_item = [[NSDraggingItem alloc] initWithPasteboardWriter:file_url];
+ [drag_item setDraggingFrame:NSMakeRect(local_pos.x - file_icon.size.width / 2, local_pos.y - file_icon.size.height / 2, file_icon.size.width, file_icon.size.height) contents:file_icon];
+ [files addObject:drag_item];
+ }
+
+ NSDraggingSession *dragging_session = [wd.window_view beginDraggingSessionWithItems:files event:event source:wd.window_view];
+ dragging_session.animatesToStartingPositionsOnCancelOrFail = YES;
+ dragging_session.draggingFormation = NSDraggingFormationNone;
+}
+
void DisplayServerMacOS::window_start_resize(DisplayServerEnums::WindowResizeEdge p_edge, DisplayServerEnums::WindowID p_window) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX(int(p_edge), DisplayServerEnums::WINDOW_EDGE_MAX);
diff --git a/platform/macos/godot_content_view.h b/platform/macos/godot_content_view.h
index d93cb291c1..45faebd53f 100644
--- a/platform/macos/godot_content_view.h
+++ b/platform/macos/godot_content_view.h
@@ -57,9 +57,9 @@
@end
GODOT_CLANG_WARNING_PUSH_AND_IGNORE("-Wdeprecated-declarations") // OpenGL is deprecated in macOS 10.14.
-@interface GodotContentView : RootView <NSTextInputClient> {
+@interface GodotContentView : RootView <NSTextInputClient, NSDraggingSource> {
DisplayServerEnums::WindowID window_id;
NSTrackingArea *tracking_area;
NSMutableAttributedString *marked_text;
bool ime_input_event_in_progress;Should we allow setting a custom preview icon for dragged files? Not sure if it will be possible on all platforms.
This makes sense to implement, but not directly related to this PR. |
@bruvzg Fantastic! This PR is based on trying to close proposal 50, which would imply work on all windowing OSes. I wanted to get feedback on if the method addition is an acceptable first step.
We should eventually; in Wayland I set the icon to nullptr, but it can be changed to a preview image. wl_data_device_start_drag(ss->wl_data_device, ss->wl_data_source_selection, window_get_wl_surface(p_window), nullptr, MAX(ss->pointer_data.button_serial, ss->last_key_pressed_serial));I don't think X11 has this feature; it would need to be coded manually, creating a window and updating it to follow the cursor, or left out. |
|
There is an XWayland bug when you drag in X11 the cursor gets stuck on the forbidden icon. https://discuss.kde.org/t/drag-and-drop-incorrect-cursor-on-xwayland/30540/5 This can be replicated in the dolphin file browser by running command: env QT_QPA_PLATFORM=xcb dolphinThis PR suffers the same exact behavior; even though it's a bug, it is working as x11 -> Wayland works. |
What problem(s) does this PR solve?
Creates Window.drag_files()
Implements new drag_files method in X11 and Wayland display servers
Testing
Drag and drop functionality manually tested with gdscript:
Additional information