Skip to content

Commit 44cfc4a

Browse files
Auto generate async functions with callbacks
We no longer need to manually implement them to drop the Send condition
1 parent f68456b commit 44cfc4a

File tree

5 files changed

+323
-264
lines changed

5 files changed

+323
-264
lines changed

gdk4/Gir.toml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,8 @@ generate_builder = false
236236
name = "set"
237237
manual = true # use ToValue
238238
[[object.function]]
239-
pattern = "(read|read_texture|read_text|read_value|store)_async"
240-
manual = true # don't enforce Send
239+
name = "read_async"
240+
manual = true # mime_types are cloned instead of converting them to a Vec<String>
241241
[[object.function]]
242242
name = "set_content"
243243
[object.function.return]
@@ -428,10 +428,7 @@ name = "Gdk.Drop"
428428
status = "generate"
429429
[[object.function]]
430430
name = "read_async"
431-
manual = true # don't require Send
432-
[[object.function]]
433-
name = "read_value_async"
434-
manual = true # don't require Send
431+
manual = true # mime_types are cloned instead of converting them to a Vec<String>
435432

436433
[[object]]
437434
name = "Gdk.FileList"

gdk4/src/auto/clipboard.rs

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use glib::translate::*;
1414
use std::boxed::Box as Box_;
1515
use std::fmt;
1616
use std::mem::transmute;
17+
use std::pin::Pin;
18+
use std::ptr;
1719

1820
glib::wrapper! {
1921
#[doc(alias = "GdkClipboard")]
@@ -48,6 +50,195 @@ impl Clipboard {
4850
unsafe { from_glib(ffi::gdk_clipboard_is_local(self.to_glib_none().0)) }
4951
}
5052

53+
#[doc(alias = "gdk_clipboard_read_text_async")]
54+
pub fn read_text_async<P: FnOnce(Result<Option<glib::GString>, glib::Error>) + 'static>(
55+
&self,
56+
cancellable: Option<&impl IsA<gio::Cancellable>>,
57+
callback: P,
58+
) {
59+
let main_context = glib::MainContext::ref_thread_default();
60+
let is_main_context_owner = main_context.is_owner();
61+
let has_acquired_main_context = (!is_main_context_owner)
62+
.then(|| main_context.acquire().ok())
63+
.flatten();
64+
assert!(
65+
is_main_context_owner || has_acquired_main_context.is_some(),
66+
"Async operations only allowed if the thread is owning the MainContext"
67+
);
68+
69+
let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
70+
Box_::new(glib::thread_guard::ThreadGuard::new(callback));
71+
unsafe extern "C" fn read_text_async_trampoline<
72+
P: FnOnce(Result<Option<glib::GString>, glib::Error>) + 'static,
73+
>(
74+
_source_object: *mut glib::gobject_ffi::GObject,
75+
res: *mut gio::ffi::GAsyncResult,
76+
user_data: glib::ffi::gpointer,
77+
) {
78+
let mut error = ptr::null_mut();
79+
let ret =
80+
ffi::gdk_clipboard_read_text_finish(_source_object as *mut _, res, &mut error);
81+
let result = if error.is_null() {
82+
Ok(from_glib_full(ret))
83+
} else {
84+
Err(from_glib_full(error))
85+
};
86+
let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
87+
Box_::from_raw(user_data as *mut _);
88+
let callback: P = callback.into_inner();
89+
callback(result);
90+
}
91+
let callback = read_text_async_trampoline::<P>;
92+
unsafe {
93+
ffi::gdk_clipboard_read_text_async(
94+
self.to_glib_none().0,
95+
cancellable.map(|p| p.as_ref()).to_glib_none().0,
96+
Some(callback),
97+
Box_::into_raw(user_data) as *mut _,
98+
);
99+
}
100+
}
101+
102+
pub fn read_text_future(
103+
&self,
104+
) -> Pin<
105+
Box_<
106+
dyn std::future::Future<Output = Result<Option<glib::GString>, glib::Error>> + 'static,
107+
>,
108+
> {
109+
Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
110+
obj.read_text_async(Some(cancellable), move |res| {
111+
send.resolve(res);
112+
});
113+
}))
114+
}
115+
116+
#[doc(alias = "gdk_clipboard_read_texture_async")]
117+
pub fn read_texture_async<P: FnOnce(Result<Option<Texture>, glib::Error>) + 'static>(
118+
&self,
119+
cancellable: Option<&impl IsA<gio::Cancellable>>,
120+
callback: P,
121+
) {
122+
let main_context = glib::MainContext::ref_thread_default();
123+
let is_main_context_owner = main_context.is_owner();
124+
let has_acquired_main_context = (!is_main_context_owner)
125+
.then(|| main_context.acquire().ok())
126+
.flatten();
127+
assert!(
128+
is_main_context_owner || has_acquired_main_context.is_some(),
129+
"Async operations only allowed if the thread is owning the MainContext"
130+
);
131+
132+
let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
133+
Box_::new(glib::thread_guard::ThreadGuard::new(callback));
134+
unsafe extern "C" fn read_texture_async_trampoline<
135+
P: FnOnce(Result<Option<Texture>, glib::Error>) + 'static,
136+
>(
137+
_source_object: *mut glib::gobject_ffi::GObject,
138+
res: *mut gio::ffi::GAsyncResult,
139+
user_data: glib::ffi::gpointer,
140+
) {
141+
let mut error = ptr::null_mut();
142+
let ret =
143+
ffi::gdk_clipboard_read_texture_finish(_source_object as *mut _, res, &mut error);
144+
let result = if error.is_null() {
145+
Ok(from_glib_full(ret))
146+
} else {
147+
Err(from_glib_full(error))
148+
};
149+
let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
150+
Box_::from_raw(user_data as *mut _);
151+
let callback: P = callback.into_inner();
152+
callback(result);
153+
}
154+
let callback = read_texture_async_trampoline::<P>;
155+
unsafe {
156+
ffi::gdk_clipboard_read_texture_async(
157+
self.to_glib_none().0,
158+
cancellable.map(|p| p.as_ref()).to_glib_none().0,
159+
Some(callback),
160+
Box_::into_raw(user_data) as *mut _,
161+
);
162+
}
163+
}
164+
165+
pub fn read_texture_future(
166+
&self,
167+
) -> Pin<Box_<dyn std::future::Future<Output = Result<Option<Texture>, glib::Error>> + 'static>>
168+
{
169+
Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
170+
obj.read_texture_async(Some(cancellable), move |res| {
171+
send.resolve(res);
172+
});
173+
}))
174+
}
175+
176+
#[doc(alias = "gdk_clipboard_read_value_async")]
177+
pub fn read_value_async<P: FnOnce(Result<glib::Value, glib::Error>) + 'static>(
178+
&self,
179+
type_: glib::types::Type,
180+
io_priority: glib::Priority,
181+
cancellable: Option<&impl IsA<gio::Cancellable>>,
182+
callback: P,
183+
) {
184+
let main_context = glib::MainContext::ref_thread_default();
185+
let is_main_context_owner = main_context.is_owner();
186+
let has_acquired_main_context = (!is_main_context_owner)
187+
.then(|| main_context.acquire().ok())
188+
.flatten();
189+
assert!(
190+
is_main_context_owner || has_acquired_main_context.is_some(),
191+
"Async operations only allowed if the thread is owning the MainContext"
192+
);
193+
194+
let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
195+
Box_::new(glib::thread_guard::ThreadGuard::new(callback));
196+
unsafe extern "C" fn read_value_async_trampoline<
197+
P: FnOnce(Result<glib::Value, glib::Error>) + 'static,
198+
>(
199+
_source_object: *mut glib::gobject_ffi::GObject,
200+
res: *mut gio::ffi::GAsyncResult,
201+
user_data: glib::ffi::gpointer,
202+
) {
203+
let mut error = ptr::null_mut();
204+
let ret =
205+
ffi::gdk_clipboard_read_value_finish(_source_object as *mut _, res, &mut error);
206+
let result = if error.is_null() {
207+
Ok(from_glib_none(ret))
208+
} else {
209+
Err(from_glib_full(error))
210+
};
211+
let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
212+
Box_::from_raw(user_data as *mut _);
213+
let callback: P = callback.into_inner();
214+
callback(result);
215+
}
216+
let callback = read_value_async_trampoline::<P>;
217+
unsafe {
218+
ffi::gdk_clipboard_read_value_async(
219+
self.to_glib_none().0,
220+
type_.into_glib(),
221+
io_priority.into_glib(),
222+
cancellable.map(|p| p.as_ref()).to_glib_none().0,
223+
Some(callback),
224+
Box_::into_raw(user_data) as *mut _,
225+
);
226+
}
227+
}
228+
229+
pub fn read_value_future(
230+
&self,
231+
type_: glib::types::Type,
232+
io_priority: glib::Priority,
233+
) -> Pin<Box_<dyn std::future::Future<Output = Result<glib::Value, glib::Error>> + 'static>>
234+
{
235+
Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
236+
obj.read_value_async(type_, io_priority, Some(cancellable), move |res| {
237+
send.resolve(res);
238+
});
239+
}))
240+
}
241+
51242
#[doc(alias = "gdk_clipboard_set_content")]
52243
pub fn set_content(
53244
&self,
@@ -81,6 +272,67 @@ impl Clipboard {
81272
}
82273
}
83274

275+
#[doc(alias = "gdk_clipboard_store_async")]
276+
pub fn store_async<P: FnOnce(Result<(), glib::Error>) + 'static>(
277+
&self,
278+
io_priority: glib::Priority,
279+
cancellable: Option<&impl IsA<gio::Cancellable>>,
280+
callback: P,
281+
) {
282+
let main_context = glib::MainContext::ref_thread_default();
283+
let is_main_context_owner = main_context.is_owner();
284+
let has_acquired_main_context = (!is_main_context_owner)
285+
.then(|| main_context.acquire().ok())
286+
.flatten();
287+
assert!(
288+
is_main_context_owner || has_acquired_main_context.is_some(),
289+
"Async operations only allowed if the thread is owning the MainContext"
290+
);
291+
292+
let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
293+
Box_::new(glib::thread_guard::ThreadGuard::new(callback));
294+
unsafe extern "C" fn store_async_trampoline<
295+
P: FnOnce(Result<(), glib::Error>) + 'static,
296+
>(
297+
_source_object: *mut glib::gobject_ffi::GObject,
298+
res: *mut gio::ffi::GAsyncResult,
299+
user_data: glib::ffi::gpointer,
300+
) {
301+
let mut error = ptr::null_mut();
302+
let _ = ffi::gdk_clipboard_store_finish(_source_object as *mut _, res, &mut error);
303+
let result = if error.is_null() {
304+
Ok(())
305+
} else {
306+
Err(from_glib_full(error))
307+
};
308+
let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
309+
Box_::from_raw(user_data as *mut _);
310+
let callback: P = callback.into_inner();
311+
callback(result);
312+
}
313+
let callback = store_async_trampoline::<P>;
314+
unsafe {
315+
ffi::gdk_clipboard_store_async(
316+
self.to_glib_none().0,
317+
io_priority.into_glib(),
318+
cancellable.map(|p| p.as_ref()).to_glib_none().0,
319+
Some(callback),
320+
Box_::into_raw(user_data) as *mut _,
321+
);
322+
}
323+
}
324+
325+
pub fn store_future(
326+
&self,
327+
io_priority: glib::Priority,
328+
) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
329+
Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
330+
obj.store_async(io_priority, Some(cancellable), move |res| {
331+
send.resolve(res);
332+
});
333+
}))
334+
}
335+
84336
#[doc(alias = "changed")]
85337
pub fn connect_changed<F: Fn(&Self) + 'static>(&self, f: F) -> SignalHandlerId {
86338
unsafe extern "C" fn changed_trampoline<F: Fn(&Clipboard) + 'static>(

gdk4/src/auto/drop.rs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@ use crate::Display;
88
use crate::Drag;
99
use crate::DragAction;
1010
use crate::Surface;
11+
use glib::object::IsA;
1112
use glib::object::ObjectType as ObjectType_;
1213
use glib::signal::connect_raw;
1314
use glib::signal::SignalHandlerId;
1415
use glib::translate::*;
1516
use std::boxed::Box as Box_;
1617
use std::fmt;
1718
use std::mem::transmute;
19+
use std::pin::Pin;
20+
use std::ptr;
1821

1922
glib::wrapper! {
2023
#[doc(alias = "GdkDrop")]
@@ -69,6 +72,71 @@ impl Drop {
6972
unsafe { from_glib_none(ffi::gdk_drop_get_surface(self.to_glib_none().0)) }
7073
}
7174

75+
#[doc(alias = "gdk_drop_read_value_async")]
76+
pub fn read_value_async<P: FnOnce(Result<glib::Value, glib::Error>) + 'static>(
77+
&self,
78+
type_: glib::types::Type,
79+
io_priority: glib::Priority,
80+
cancellable: Option<&impl IsA<gio::Cancellable>>,
81+
callback: P,
82+
) {
83+
let main_context = glib::MainContext::ref_thread_default();
84+
let is_main_context_owner = main_context.is_owner();
85+
let has_acquired_main_context = (!is_main_context_owner)
86+
.then(|| main_context.acquire().ok())
87+
.flatten();
88+
assert!(
89+
is_main_context_owner || has_acquired_main_context.is_some(),
90+
"Async operations only allowed if the thread is owning the MainContext"
91+
);
92+
93+
let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
94+
Box_::new(glib::thread_guard::ThreadGuard::new(callback));
95+
unsafe extern "C" fn read_value_async_trampoline<
96+
P: FnOnce(Result<glib::Value, glib::Error>) + 'static,
97+
>(
98+
_source_object: *mut glib::gobject_ffi::GObject,
99+
res: *mut gio::ffi::GAsyncResult,
100+
user_data: glib::ffi::gpointer,
101+
) {
102+
let mut error = ptr::null_mut();
103+
let ret = ffi::gdk_drop_read_value_finish(_source_object as *mut _, res, &mut error);
104+
let result = if error.is_null() {
105+
Ok(from_glib_none(ret))
106+
} else {
107+
Err(from_glib_full(error))
108+
};
109+
let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
110+
Box_::from_raw(user_data as *mut _);
111+
let callback: P = callback.into_inner();
112+
callback(result);
113+
}
114+
let callback = read_value_async_trampoline::<P>;
115+
unsafe {
116+
ffi::gdk_drop_read_value_async(
117+
self.to_glib_none().0,
118+
type_.into_glib(),
119+
io_priority.into_glib(),
120+
cancellable.map(|p| p.as_ref()).to_glib_none().0,
121+
Some(callback),
122+
Box_::into_raw(user_data) as *mut _,
123+
);
124+
}
125+
}
126+
127+
pub fn read_value_future(
128+
&self,
129+
type_: glib::types::Type,
130+
io_priority: glib::Priority,
131+
) -> Pin<Box_<dyn std::future::Future<Output = Result<glib::Value, glib::Error>> + 'static>>
132+
{
133+
Box_::pin(gio::GioFuture::new(self, move |obj, cancellable, send| {
134+
obj.read_value_async(type_, io_priority, Some(cancellable), move |res| {
135+
send.resolve(res);
136+
});
137+
}))
138+
}
139+
72140
#[doc(alias = "gdk_drop_status")]
73141
pub fn status(&self, actions: DragAction, preferred: DragAction) {
74142
unsafe {

0 commit comments

Comments
 (0)