gtk4/drop_target.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem::transmute};
4
5use glib::{
6 signal::{connect_raw, SignalHandlerId},
7 translate::*,
8 value::FromValue,
9 Slice, Type,
10};
11
12use crate::{ffi, prelude::*, DropTarget};
13
14impl DropTarget {
15 /// Sets the supported `GType`s for this drop target.
16 /// ## `types`
17 /// all supported `GType`s
18 /// that can be dropped on the target
19 #[doc(alias = "gtk_drop_target_set_gtypes")]
20 pub fn set_types(&self, types: &[Type]) {
21 let types: Vec<glib::ffi::GType> = types.iter().map(|t| t.into_glib()).collect();
22 unsafe {
23 ffi::gtk_drop_target_set_gtypes(
24 self.to_glib_none().0,
25 mut_override(types.as_ptr()),
26 types.len(),
27 )
28 }
29 }
30
31 #[doc(alias = "gtk_drop_target_get_value")]
32 #[doc(alias = "get_value")]
33 // rustdoc-stripper-ignore-next
34 /// Similar to [`Self::value`] but panics if the value is of a different
35 /// type.
36 pub fn value_as<V: for<'b> FromValue<'b> + 'static>(&self) -> Option<V> {
37 self.value().map(|v| {
38 v.get_owned::<V>()
39 .expect("Failed to get value as this type")
40 })
41 }
42
43 /// Gets the list of supported `GType`s that can be dropped on the target.
44 ///
45 /// If no types have been set, `NULL` will be returned.
46 ///
47 /// # Returns
48 ///
49 ///
50 /// the `G_TYPE_INVALID`-terminated array of types included in
51 /// formats
52 #[doc(alias = "gtk_drop_target_get_gtypes")]
53 #[doc(alias = "get_gtypes")]
54 pub fn types(&self) -> Slice<Type> {
55 unsafe {
56 let mut n_types = std::mem::MaybeUninit::uninit();
57 let types =
58 ffi::gtk_drop_target_get_gtypes(self.to_glib_none().0, n_types.as_mut_ptr());
59
60 Slice::from_glib_none_num(types, n_types.assume_init() as _)
61 }
62 }
63
64 // Returns true if the drop was accepted
65 /// Emitted on the drop site when the user drops the data onto the widget.
66 ///
67 /// The signal handler must determine whether the pointer position is in
68 /// a drop zone or not. If it is not in a drop zone, it returns [`false`]
69 /// and no further processing is necessary.
70 ///
71 /// Otherwise, the handler returns [`true`]. In this case, this handler will
72 /// accept the drop. The handler is responsible for using the given @value
73 /// and performing the drop operation.
74 /// ## `value`
75 /// the `GValue` being dropped
76 /// ## `x`
77 /// the x coordinate of the current pointer position
78 /// ## `y`
79 /// the y coordinate of the current pointer position
80 ///
81 /// # Returns
82 ///
83 /// whether the drop was accepted at the given pointer position
84 pub fn connect_drop<F: Fn(&DropTarget, &glib::Value, f64, f64) -> bool + 'static>(
85 &self,
86 f: F,
87 ) -> SignalHandlerId {
88 unsafe extern "C" fn drop_trampoline<
89 F: Fn(&DropTarget, &glib::Value, f64, f64) -> bool + 'static,
90 >(
91 this: *mut ffi::GtkDropTarget,
92 value: *mut glib::gobject_ffi::GValue,
93 x: libc::c_double,
94 y: libc::c_double,
95 f: glib::ffi::gpointer,
96 ) -> glib::ffi::gboolean {
97 let f: &F = &*(f as *const F);
98 f(
99 &from_glib_borrow(this),
100 &*(value as *const glib::Value),
101 x,
102 y,
103 )
104 .into_glib()
105 }
106 unsafe {
107 let f: Box_<F> = Box_::new(f);
108 connect_raw(
109 self.as_ptr() as *mut _,
110 b"drop\0".as_ptr() as *const _,
111 Some(transmute::<*const (), unsafe extern "C" fn()>(
112 drop_trampoline::<F> as *const (),
113 )),
114 Box_::into_raw(f),
115 )
116 }
117 }
118}