[gtk-rs] Passing Widget as GValue through Drag and drop with composite template

Hello, I am looking for a bit of help regarding Drag and Drop with gtk-rs please.
I use the composite template feature.
I have a widget FooFrame, subclass of gtkFrame. It contains another pok_frame gtk::Frame and a target gtk::Box to receive the drop.
The goal is to be able to get a reference for the Frame widget that was dragged and dropped onto the target box.

/// FooFrame widget Subclass of Gtk::Frame widget
 #[derive(Debug, Default, CompositeTemplate)]
 #[template(resource = "/ui/layout.ui")]
 pub struct FooFrame {
    #[template_child]
    pub target_box: TemplateChild<gtk::Box>,
    #[template_child]
    pub pok_frame: TemplateChild<gtk::Frame>,
 }

I call a function to setup a DragSource in

impl ObjectImpl for FooFrame {
        fn constructed(&self) {
            self.parent_constructed();
            
            self.obj().set_drag();
        }
}

Details of the setup function and the “on_drop” callback for drop signal:

#[gtk::template_callbacks]
impl FooFrame {
    /// Setup DragSource.
    fn set_drag(&self) {
        let frame: gtk::Frame = self.imp().pok_frame.get();
        
        let drag = gtk::DragSource::new();
        drag.set_actions(gtk::gdk::DragAction::COPY);

        drag.connect_prepare(
        clone!(@weak frame => @default-return None, move |_, _, _| Some(ContentProvider::for_value(&frame.to_value()))));

        frame.add_controller(drag);
    }
        
    /// Callback used for drop signal.
    #[template_callback]
    pub fn on_drop(&self, value: &glib::Value, x: f64, y: f64) -> bool {
        // Program panic here
        let res_frame: Frame = value.get().expect("Error getting GtkFrame from Drop");
	
	// Do something after.
        info!("In connect_drop. Drop at {x} {y}");
        true
    }
}

The DropTarget is define in the XML file of FooFrame.

XML definition of the widget:

<?xml version='1.0' encoding='UTF-8'?>
<interface>
  <template class="FooFrame" parent="GtkFrame">
    <child>
      <object class="GtkBox" id="target_box">
        <child>
          <object class="GtkDropTarget" id="drop_target">
            <property name="actions">copy</property>
            <property name="formats">GtkFrame</property>
            <signal name="drop" handler="on_drop" swapped="true"/>
          </object>
        </child>
        <child>
          <object class="GtkBox">
            <child>
              <object class="GtkFrame" id="pok_frame"/>
            </child>
          </object>
        </child>
    </child>
  </template>
</interface>

I run the app, drag the frame widget and drop it on the frame target. The app panic and output:

thread ‘main’ panicked at ‘Error getting GtkFrame from Drop: WrongValueType(ValueTypeMismatchError { actual: GValue, requested: GtkFrame })’

I would like to get the GtkFrame but I manage only to get a GValue which can’t, obviously, be “converted” into GtkFrame.
I don’t understand what is wrong with my setup and how GtkFrame value is passed with the DropTarget.
Is there something obviously wrong in my setup please?

Thanks for your time.

Hello, this is a quirk of the way the Rust bindings work and should probably be documented better. Using a glib::Value will give you the raw value passed to the closure but will not work right when the argument itself is a Value. To get a Value that is “inside” another Value you have to use BoxedValue:

    pub fn on_drop(&self, value: glib::BoxedValue, x: f64, y: f64) -> bool {
        // ...
   }

Thanks a lot!

It works like a charm now. I agree that the documentation should reflect this because this is impossible/very hard to guess otherwise.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.