picoe / Eto

Cross platform GUI framework for desktop and mobile applications in .NET
Other
3.57k stars 325 forks source link

Gtk drag-and-drop from external applications does not work #2492

Closed snake-scaly closed 1 year ago

snake-scaly commented 1 year ago

Expected Behavior

The Control.OnDragEnter, Control.OnDragDrop and friends should allow drag data introspection and retrieval. E.g. if DragEventArgs.Data.ContainsUris is true then DragEventArgs.Data.Uris should be a non-empty array of URIs.

Actual Behavior

An attempt to access the DragEventArgs.Data.Uris property crashes with a NullReferenceException.

Steps to Reproduce the Problem

You can use my project https://github.com/snake-scaly/PinBoard to reproduce the issue. It should support dragging and dropping images from a file manager, an image viewer, or a web browser onto the canvas. The most straightforward test is to drag an image from a file manager and drop it onto the application.

See the BoardView class for the relevant code. For me it is 100% reproducible, AKA never works.

Analysis

The problem is that Gtk drag-and-drop model is arguably incompatible with Eto architecture. This is not a design flaw on the Eto part, this is just the way things are. The main problems are:

Solution

https://github.com/picoe/Eto/compare/develop...snake-scaly:Eto:feature/drag-drop-fix

I've made a patch that solves this issue for me. My approach is to request and cache data for all targets in the context, in the normal message loop, before calling OnDragEnter. Then I destroy that data on drag-leave, and request it again if drag-drop happens. This is very resource-intensive, because if there are 7 targets in the context, all 7 will be requested and stored even though many are duplicates, and most will never be requested by the application. This however allows me to stay within the normal message loop and therefore have a predictable state machine in the handler.

Specifications

snake-scaly commented 1 year ago

I've tested my application on a vanilla Kubuntu with Eto.Platforms.Gtk 2.7.5. The crash is 100% reproducible there when a Drop handler attempts to get Uris from the drop event.

My fix worked well for me so far. All drag and drop scenarios which I needed worked correctly. However I didn't do any extensive testing which would require trying this in multiple operating systems and desktop environments.