Skip to main content

gtk4/
functions.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_, pin::Pin, sync::OnceLock};
4
5use glib::{Quark, Slice, translate::*};
6
7pub use crate::auto::functions::*;
8use crate::{AboutDialog, StyleProvider, Window, ffi, prelude::*};
9
10///  accelerator. But, you can't, for instance, use
11/// the `GDK_KEY_Control_L` keyval as an accelerator.
12/// ## `keyval`
13/// a GDK keyval
14/// ## `modifiers`
15/// modifier mask
16///
17/// # Returns
18///
19/// true if the accelerator is valid
20#[doc(alias = "gtk_accelerator_valid")]
21pub fn accelerator_valid(keyval: gdk::Key, modifiers: gdk::ModifierType) -> bool {
22    assert_initialized_main_thread!();
23    unsafe {
24        from_glib(ffi::gtk_accelerator_valid(
25            keyval.into_glib(),
26            modifiers.into_glib(),
27        ))
28    }
29}
30
31/// Converts an accelerator keyval and modifier mask into a string
32/// which can be used to represent the accelerator to the user.
33/// ## `accelerator_key`
34/// accelerator keyval
35/// ## `accelerator_mods`
36/// accelerator modifier mask
37///
38/// # Returns
39///
40/// a newly-allocated string representing the accelerator
41#[doc(alias = "gtk_accelerator_get_label")]
42pub fn accelerator_get_label(
43    accelerator_key: gdk::Key,
44    accelerator_mods: gdk::ModifierType,
45) -> glib::GString {
46    assert_initialized_main_thread!();
47    unsafe {
48        from_glib_full(ffi::gtk_accelerator_get_label(
49            accelerator_key.into_glib(),
50            accelerator_mods.into_glib(),
51        ))
52    }
53}
54
55/// Converts an accelerator keyval and modifier mask
56/// into a string that can be displayed to the user.
57///
58/// The string may be translated.
59///
60/// This function is similar to [`accelerator_get_label()`][crate::accelerator_get_label()],
61/// but handling keycodes. This is only useful for system-level
62/// components, applications should use [`accelerator_get_label()`][crate::accelerator_get_label()]
63/// instead.
64/// ## `display`
65/// a [`gdk::Display`][crate::gdk::Display]
66/// ## `accelerator_key`
67/// accelerator keyval
68/// ## `keycode`
69/// accelerator keycode
70/// ## `accelerator_mods`
71/// accelerator modifier mask
72///
73/// # Returns
74///
75/// a newly-allocated string representing the accelerator
76#[doc(alias = "gtk_accelerator_get_label_with_keycode")]
77pub fn accelerator_get_label_with_keycode(
78    display: Option<&impl IsA<gdk::Display>>,
79    accelerator_key: gdk::Key,
80    keycode: u32,
81    accelerator_mods: gdk::ModifierType,
82) -> glib::GString {
83    assert_initialized_main_thread!();
84    unsafe {
85        from_glib_full(ffi::gtk_accelerator_get_label_with_keycode(
86            display.map(|p| p.as_ref()).to_glib_none().0,
87            accelerator_key.into_glib(),
88            keycode,
89            accelerator_mods.into_glib(),
90        ))
91    }
92}
93
94/// q`.
95///
96/// If you need to display accelerators in the user interface,
97/// see [`accelerator_get_label()`][crate::accelerator_get_label()].
98/// ## `accelerator_key`
99/// accelerator keyval
100/// ## `accelerator_mods`
101/// accelerator modifier mask
102///
103/// # Returns
104///
105/// a newly-allocated accelerator name
106#[doc(alias = "gtk_accelerator_name")]
107pub fn accelerator_name(
108    accelerator_key: gdk::Key,
109    accelerator_mods: gdk::ModifierType,
110) -> glib::GString {
111    assert_initialized_main_thread!();
112    unsafe {
113        from_glib_full(ffi::gtk_accelerator_name(
114            accelerator_key.into_glib(),
115            accelerator_mods.into_glib(),
116        ))
117    }
118}
119
120/// Converts an accelerator keyval and modifier mask
121/// into a string that can be parsed by [`accelerator_parse_with_keycode()`][crate::accelerator_parse_with_keycode()].
122///
123/// This is similar to [`accelerator_name()`][crate::accelerator_name()] but handling keycodes.
124/// This is only useful for system-level components, applications
125/// should use [`accelerator_name()`][crate::accelerator_name()] instead.
126/// ## `display`
127/// a [`gdk::Display`][crate::gdk::Display]
128/// ## `accelerator_key`
129/// accelerator keyval
130/// ## `keycode`
131/// accelerator keycode
132/// ## `accelerator_mods`
133/// accelerator modifier mask
134///
135/// # Returns
136///
137/// a newly allocated accelerator name.
138#[doc(alias = "gtk_accelerator_name_with_keycode")]
139pub fn accelerator_name_with_keycode(
140    display: Option<&impl IsA<gdk::Display>>,
141    accelerator_key: gdk::Key,
142    keycode: u32,
143    accelerator_mods: gdk::ModifierType,
144) -> glib::GString {
145    assert_initialized_main_thread!();
146    unsafe {
147        from_glib_full(ffi::gtk_accelerator_name_with_keycode(
148            display.map(|p| p.as_ref()).to_glib_none().0,
149            accelerator_key.into_glib(),
150            keycode,
151            accelerator_mods.into_glib(),
152        ))
153    }
154}
155
156/// ` for `GDK_HYPER_MASK`
157///
158/// If the parse operation fails, @accelerator_key and @accelerator_mods will
159/// be set to 0 (zero).
160/// ## `accelerator`
161/// string representing an accelerator
162///
163/// # Returns
164///
165/// whether parsing succeeded
166///
167/// ## `accelerator_key`
168/// return location for accelerator keyval
169///
170/// ## `accelerator_mods`
171/// return location for accelerator
172///   modifier mask
173#[doc(alias = "gtk_accelerator_parse")]
174pub fn accelerator_parse(accelerator: impl IntoGStr) -> Option<(gdk::Key, gdk::ModifierType)> {
175    assert_initialized_main_thread!();
176    unsafe {
177        accelerator.run_with_gstr(|accelerator| {
178            let mut accelerator_key = std::mem::MaybeUninit::uninit();
179            let mut accelerator_mods = std::mem::MaybeUninit::uninit();
180            let ret = from_glib(ffi::gtk_accelerator_parse(
181                accelerator.as_ptr(),
182                accelerator_key.as_mut_ptr(),
183                accelerator_mods.as_mut_ptr(),
184            ));
185            if ret {
186                Some((
187                    gdk::Key::from_glib(accelerator_key.assume_init()),
188                    from_glib(accelerator_mods.assume_init()),
189                ))
190            } else {
191                None
192            }
193        })
194    }
195}
196
197/// Parses a string representing an accelerator.
198///
199/// This is similar to [`accelerator_parse()`][crate::accelerator_parse()] but handles keycodes as
200/// well. This is only useful for system-level components, applications should
201/// use [`accelerator_parse()`][crate::accelerator_parse()] instead.
202///
203/// If @accelerator_codes is given and the result stored in it is non-[`None`],
204/// the result must be freed with g_free().
205///
206/// If a keycode is present in the accelerator and no @accelerator_codes
207/// is given, the parse will fail.
208///
209/// If the parse fails, @accelerator_key, @accelerator_mods and
210/// @accelerator_codes will be set to 0 (zero).
211/// ## `accelerator`
212/// string representing an accelerator
213/// ## `display`
214/// the [`gdk::Display`][crate::gdk::Display] to look up @accelerator_codes in
215///
216/// # Returns
217///
218/// true if parsing succeeded
219///
220/// ## `accelerator_key`
221/// return location for accelerator keyval
222///
223/// ## `accelerator_codes`
224///
225///   return location for accelerator keycodes
226///
227/// ## `accelerator_mods`
228/// return location for accelerator
229///   modifier mask
230#[doc(alias = "gtk_accelerator_parse_with_keycode")]
231pub fn accelerator_parse_with_keycode(
232    accelerator: impl IntoGStr,
233    display: Option<&impl IsA<gdk::Display>>,
234) -> Option<(gdk::Key, Slice<u32>, gdk::ModifierType)> {
235    assert_initialized_main_thread!();
236    unsafe {
237        accelerator.run_with_gstr(|accelerator| {
238            let mut accelerator_key = std::mem::MaybeUninit::uninit();
239            let mut accelerator_codes_ptr = std::ptr::null_mut();
240            let mut accelerator_mods = std::mem::MaybeUninit::uninit();
241            let success = from_glib(ffi::gtk_accelerator_parse_with_keycode(
242                accelerator.as_ptr(),
243                display.map(|p| p.as_ref()).to_glib_none().0,
244                accelerator_key.as_mut_ptr(),
245                &mut accelerator_codes_ptr,
246                accelerator_mods.as_mut_ptr(),
247            ));
248            if success {
249                let mut len = 0;
250                if !accelerator_codes_ptr.is_null() {
251                    while std::ptr::read(accelerator_codes_ptr.add(len)) != 0 {
252                        len += 1;
253                    }
254                }
255                let accelerator_codes = Slice::from_glib_full_num(accelerator_codes_ptr, len);
256                Some((
257                    gdk::Key::from_glib(accelerator_key.assume_init()),
258                    accelerator_codes,
259                    from_glib(accelerator_mods.assume_init()),
260                ))
261            } else {
262                None
263            }
264        })
265    }
266}
267
268/// This function launches the default application for showing
269/// a given uri.
270///
271/// The @callback will be called when the launch is completed.
272///
273/// This is the recommended call to be used as it passes information
274/// necessary for sandbox helpers to parent their dialogs properly.
275///
276/// # Deprecated since 4.10
277///
278/// Use [`FileLauncher::launch()`][crate::FileLauncher::launch()] or
279///   [`UriLauncher::launch()`][crate::UriLauncher::launch()] instead
280/// ## `parent`
281/// parent window
282/// ## `uri`
283/// the uri to show
284/// ## `timestamp`
285/// timestamp from the event that triggered this call, or `GDK_CURRENT_TIME`
286/// ## `cancellable`
287/// a `GCancellable` to cancel the launch
288/// ## `callback`
289/// a callback to call when the action is complete
290#[doc(alias = "gtk_show_uri_full")]
291#[doc(alias = "gtk_show_uri_full_finish")]
292#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
293#[allow(deprecated)]
294pub fn show_uri_full<P: FnOnce(Result<(), glib::Error>) + 'static>(
295    parent: Option<&impl IsA<Window>>,
296    uri: &str,
297    timestamp: u32,
298    cancellable: Option<&impl IsA<gio::Cancellable>>,
299    callback: P,
300) {
301    assert_initialized_main_thread!();
302    let main_context = glib::MainContext::ref_thread_default();
303    let is_main_context_owner = main_context.is_owner();
304    let has_acquired_main_context = (!is_main_context_owner)
305        .then(|| main_context.acquire().ok())
306        .flatten();
307    assert!(
308        is_main_context_owner || has_acquired_main_context.is_some(),
309        "Async operations only allowed if the thread is owning the MainContext"
310    );
311
312    let user_data: Box_<glib::thread_guard::ThreadGuard<P>> =
313        Box_::new(glib::thread_guard::ThreadGuard::new(callback));
314    unsafe extern "C" fn show_uri_full_trampoline<P: FnOnce(Result<(), glib::Error>) + 'static>(
315        parent_ptr: *mut glib::gobject_ffi::GObject,
316        res: *mut gio::ffi::GAsyncResult,
317        user_data: glib::ffi::gpointer,
318    ) {
319        unsafe {
320            let mut error = std::ptr::null_mut();
321            let _ =
322                ffi::gtk_show_uri_full_finish(parent_ptr as *mut ffi::GtkWindow, res, &mut error);
323            let result = if error.is_null() {
324                Ok(())
325            } else {
326                Err(from_glib_full(error))
327            };
328            let callback: Box_<glib::thread_guard::ThreadGuard<P>> =
329                Box_::from_raw(user_data as *mut _);
330            let callback = callback.into_inner();
331            callback(result);
332        }
333    }
334    let callback = show_uri_full_trampoline::<P>;
335    unsafe {
336        ffi::gtk_show_uri_full(
337            parent.map(|p| p.as_ref()).to_glib_none().0,
338            uri.to_glib_none().0,
339            timestamp,
340            cancellable.map(|p| p.as_ref()).to_glib_none().0,
341            Some(callback),
342            Box_::into_raw(user_data) as *mut _,
343        );
344    }
345}
346
347#[cfg_attr(feature = "v4_10", deprecated = "Since 4.10")]
348#[allow(deprecated)]
349pub fn show_uri_full_future(
350    parent: Option<&(impl IsA<Window> + Clone + 'static)>,
351    uri: &str,
352    timestamp: u32,
353) -> Pin<Box_<dyn std::future::Future<Output = Result<(), glib::Error>> + 'static>> {
354    skip_assert_initialized!();
355    let parent = parent.map(ToOwned::to_owned);
356    let uri = String::from(uri);
357    Box_::pin(gio::GioFuture::new(&(), move |_obj, cancellable, send| {
358        show_uri_full(
359            parent.as_ref().map(::std::borrow::Borrow::borrow),
360            &uri,
361            timestamp,
362            Some(cancellable),
363            move |res| {
364                send.resolve(res);
365            },
366        );
367    }))
368}
369
370/// s about dialog.
371///
372/// The constructed dialog is associated with the parent window and
373/// reused for future invocations of this function.
374/// ## `parent`
375/// the parent top-level window
376/// ## `first_property_name`
377/// the name of the first property
378#[doc(alias = "gtk_show_about_dialog")]
379pub fn show_about_dialog<P: IsA<Window>>(parent: Option<&P>, properties: &[(&str, &dyn ToValue)]) {
380    assert_initialized_main_thread!();
381    static QUARK: OnceLock<Quark> = OnceLock::new();
382    let quark = *QUARK.get_or_init(|| Quark::from_str("gtk-rs-about-dialog"));
383
384    unsafe {
385        if let Some(d) = parent.and_then(|p| p.qdata::<AboutDialog>(quark)) {
386            d.as_ref().show();
387        } else {
388            let mut builder = glib::Object::builder::<AboutDialog>();
389            for (key, value) in properties {
390                builder = builder.property(key, *value);
391            }
392            let about_dialog = builder.build();
393            about_dialog.set_hide_on_close(true);
394
395            // cache the dialog if a parent is set
396            if let Some(dialog_parent) = parent {
397                about_dialog.set_modal(true);
398                about_dialog.set_transient_for(parent);
399                about_dialog.set_destroy_with_parent(true);
400                dialog_parent.set_qdata(quark, about_dialog.clone());
401            }
402
403            about_dialog.show();
404        };
405    }
406}
407
408/// Return the type ids that have been registered after
409/// calling gtk_test_register_all_types().
410///
411/// # Returns
412///
413///
414///    0-terminated array of type ids
415#[doc(alias = "gtk_test_list_all_types")]
416pub fn test_list_all_types() -> Slice<glib::Type> {
417    unsafe {
418        let mut n_types = std::mem::MaybeUninit::uninit();
419        let types = ffi::gtk_test_list_all_types(n_types.as_mut_ptr());
420        Slice::from_glib_container_num(types as *mut _, n_types.assume_init() as usize)
421    }
422}
423
424#[doc(alias = "gtk_style_context_add_provider_for_display")]
425#[doc(alias = "add_provider_for_display")]
426pub fn style_context_add_provider_for_display(
427    display: &impl IsA<gdk::Display>,
428    provider: &impl IsA<StyleProvider>,
429    priority: u32,
430) {
431    skip_assert_initialized!();
432    unsafe {
433        ffi::gtk_style_context_add_provider_for_display(
434            display.as_ref().to_glib_none().0,
435            provider.as_ref().to_glib_none().0,
436            priority,
437        );
438    }
439}
440
441#[doc(alias = "gtk_style_context_remove_provider_for_display")]
442#[doc(alias = "remove_provider_for_display")]
443pub fn style_context_remove_provider_for_display(
444    display: &impl IsA<gdk::Display>,
445    provider: &impl IsA<StyleProvider>,
446) {
447    skip_assert_initialized!();
448    unsafe {
449        ffi::gtk_style_context_remove_provider_for_display(
450            display.as_ref().to_glib_none().0,
451            provider.as_ref().to_glib_none().0,
452        );
453    }
454}