Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[HELP] drag and drop a custom rust struct #1442

Open
eppixx opened this issue Jul 30, 2023 · 6 comments
Open

[HELP] drag and drop a custom rust struct #1442

eppixx opened this issue Jul 30, 2023 · 6 comments

Comments

@eppixx
Copy link

eppixx commented Jul 30, 2023

I want to implement some drag and drop.
Sending a String works fine, but sending a struct is difficult for me.
I found BoxedAnyObject which can be compiled without issue like so:

struct Author {
    name: String,
    subscribers: usize,
}
// ...
        // prepare dragging source
        let boxed = glib::BoxedAnyObject::new(Author {
            name: String::from("GLibAuthor"),
            subscribers: 1000,
        });
        let content = gdk::ContentProvider::for_value(&boxed.to_value());
        model.drag_src.set_content(Some(&content));
        model.drag_src.set_actions(gdk::DragAction::MOVE);
// ...

Problem is I can't receive the drop with any Type set on DropTarget.
I expect it something to do with the following logging:
Gdk-CRITICAL **: 02:49:32.415: gdk_content_formats_builder_add_gtype: assertion 'type != G_TYPE_INVALID' failed

Is the way I'm trying to do this wrong or is there a better way to do this?

@eppixx
Copy link
Author

eppixx commented Aug 1, 2023

I managed to find out where the error comes from. Problem was the types I accepted with set_types on the DropTarget.

I also found out I need to I need to call connect_accept on DropTarget instead of using set_types that implements a custom check if the Drop can be accepted.

This works for a String in the following way in connect_drop

//function connect_drop
    let any = value.get::<String>();
    //work with any

But when using BoxedAnyObject instead of String my application freezes with the following logs:

Glib-GObject-WARNING **: 18:06:30.439: ../../../gobject/gtype.c:4333: type id '0' is invalid
Glib-GObject-WARNING **: 18:06:30.446: can't peek value table for type '<invalid>' which is not currently referenced
Glib-GObject-WARNING **: 18:06:30.446: ../../../gobject/gvalue.c:218: cannot initialize GValue with type '(null)', this type has no GTypeValueTable implementation 
Gdk-CRITICAL **: 18:06:30.447: gdk_content_provider_get_value: assertion 'G_IS_VALUE (value)' failed
Glib-GObject-WARNING **: 18:06:30.447: ../../../gobject/gtype.c:4333: type id '0' is invalid
Glib-GObject-WARNING **: 18:06:30.447: can't peek value table for type '<invalid>' which is not currently referenced
Glib-GObject-WARNING **: 18:06:30.447: ../../../gobject/gvalue.c:218: cannot initialize GValue with type '(null)', this type has no GTypeValueTable implementation 
Gdk-CRITICAL **: 18:06:30.447: gdk_content_provider_get_value: assertion 'G_IS_VALUE (value)' failed
Glib-GIO-CRITICAL **: 18:06:30.447: g_task_return_error 'error != NULL' failed

This is logged before connect _drop is called.
The error suggests that the drop is not a gobject but isn't that what BoxedAnyObject is for?

@bilelmoussaoui
Copy link
Member

Please share a link to a repo with an easy to reproduce example. Otherwise no one can help you.

@bilelmoussaoui
Copy link
Member

Also please use https://github.com/gtk-rs/gtk4-rs/discussions instead of the issue tracker when asking questions.

@eppixx
Copy link
Author

eppixx commented Aug 1, 2023

I created a repo here https://github.com/eppixx/gtk4-dnd

The relevant file is in factory/queue_item.rs

@eppixx
Copy link
Author

eppixx commented Aug 9, 2023

I found out that transfering a struct is possible by deriving glib::Boxed like in https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/subclass/index.html#example-for-registering-a-boxed-type-for-a-rust-struct.
Then the DropTarget needs to set_types to $STRUCT::static_type().
An abridged version:

#[derive(Clone, glib::Boxed)]
#[boxed_type(name = "Test")]
struct Test;

// snip

let src = gtk::DragSource::new();
src.set_actions(gdk::DragAction::MOVE);
src.set_content(Some(&gdk::ContentProvider::for_value(&Test.to_value())));

let dest = gtk::DropTarget::new();
dest.set_actions(gdk::DragAction::MOVE):
dest.set_types(&[Test::static_type()]);
dest.connect_drop(move |_widget, value, _x, _y| {
    if let Ok(_test) = value::get::<Test>() {
        // work with test here
    }
    true
});

That solves the part of dropping a custom rust struct, but doesn't explain why the other way doesn't. This can be closed if the behaviour is not deemed a bug.

@bilelmoussaoui
Copy link
Member

I found out that transfering a struct is possible by deriving glib::Boxed like in https://gtk-rs.org/gtk-rs-core/stable/latest/docs/glib/subclass/index.html#example-for-registering-a-boxed-type-for-a-rust-struct.
Then the DropTarget needs to set_types to $STRUCT::static_type().

It should work the same with BoxedAnyObject, you would have to call set_types like you did here.

That solves the part of dropping a custom rust struct, but doesn't explain why the other way doesn't. This can be closed if the behaviour is not deemed a bug.

Wdym by the "other way"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants