1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
// Take a look at the license at the top of the repository in the LICENSE file.

#[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
use std::boxed::Box as Box_;
#[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
use std::os::unix::io::AsRawFd;
#[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
use std::ptr;

#[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
use glib::Error;
use glib::{prelude::*, translate::*, GString};

#[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
use crate::AppLaunchContext;
use crate::DesktopAppInfo;

impl DesktopAppInfo {
    /// Searches desktop files for ones that match `search_string`.
    ///
    /// The return value is an array of strvs. Each strv contains a list of
    /// applications that matched `search_string` with an equal score. The
    /// outer list is sorted by score so that the first strv contains the
    /// best-matching applications, and so on.
    /// The algorithm for determining matches is undefined and may change at
    /// any time.
    ///
    /// None of the search results are subjected to the normal validation
    /// checks performed by [`new()`][Self::new()] (for example, checking that
    /// the executable referenced by a result exists), and so it is possible for
    /// [`new()`][Self::new()] to return [`None`] when passed an app ID returned by
    /// this function. It is expected that calling code will do this when
    /// subsequently creating a [`DesktopAppInfo`][crate::DesktopAppInfo] for each result.
    /// ## `search_string`
    /// the search string to use
    ///
    /// # Returns
    ///
    /// a
    ///  list of strvs. Free each item with `g_strfreev()` and free the outer
    ///  list with `g_free()`.
    #[doc(alias = "g_desktop_app_info_search")]
    pub fn search(search_string: &str) -> Vec<Vec<GString>> {
        unsafe {
            let out = ffi::g_desktop_app_info_search(search_string.to_glib_none().0);

            if out.is_null() {
                return Vec::new();
            }

            let mut ret = Vec::new();
            let mut it = 0;
            loop {
                let tmp: *mut *mut libc::c_char = *out.offset(it);

                if tmp.is_null() {
                    break;
                }
                let v: Vec<GString> = FromGlibPtrContainer::from_glib_full(tmp);
                ret.push(v);
                it += 1;
            }

            glib::ffi::g_free(out as *mut libc::c_void);
            ret
        }
    }
}

pub trait DesktopAppInfoExtManual {
    #[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
    #[cfg_attr(feature = "dox", doc(cfg(all(feature = "v2_58", unix))))]
    #[doc(alias = "g_desktop_app_info_launch_uris_as_manager_with_fds")]
    fn launch_uris_as_manager_with_fds<
        P: IsA<AppLaunchContext>,
        T: AsRawFd,
        U: AsRawFd,
        V: AsRawFd,
    >(
        &self,
        uris: &[&str],
        launch_context: Option<&P>,
        spawn_flags: glib::SpawnFlags,
        user_setup: Option<Box_<dyn FnOnce() + 'static>>,
        pid_callback: Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))>,
        stdin_fd: &mut T,
        stdout_fd: &mut U,
        stderr_fd: &mut V,
    ) -> Result<(), Error>;
}

impl<O: IsA<DesktopAppInfo>> DesktopAppInfoExtManual for O {
    #[cfg(any(all(feature = "v2_58", unix), all(unix, feature = "dox")))]
    #[cfg_attr(feature = "dox", doc(cfg(all(feature = "v2_58", unix))))]
    fn launch_uris_as_manager_with_fds<
        P: IsA<AppLaunchContext>,
        T: AsRawFd,
        U: AsRawFd,
        V: AsRawFd,
    >(
        &self,
        uris: &[&str],
        launch_context: Option<&P>,
        spawn_flags: glib::SpawnFlags,
        user_setup: Option<Box_<dyn FnOnce() + 'static>>,
        pid_callback: Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))>,
        stdin_fd: &mut T,
        stdout_fd: &mut U,
        stderr_fd: &mut V,
    ) -> Result<(), Error> {
        let user_setup_data: Box_<Option<Box_<dyn FnOnce() + 'static>>> = Box_::new(user_setup);
        unsafe extern "C" fn user_setup_func(user_data: glib::ffi::gpointer) {
            let callback: Box_<Option<Box_<dyn FnOnce() + 'static>>> =
                Box_::from_raw(user_data as *mut _);
            let callback = (*callback).expect("cannot get closure...");
            callback()
        }
        let user_setup = if user_setup_data.is_some() {
            Some(user_setup_func as _)
        } else {
            None
        };
        let pid_callback_data: Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))> = pid_callback;
        unsafe extern "C" fn pid_callback_func(
            appinfo: *mut ffi::GDesktopAppInfo,
            pid: glib::ffi::GPid,
            user_data: glib::ffi::gpointer,
        ) {
            let appinfo = from_glib_borrow(appinfo);
            let pid = from_glib(pid);
            let callback: *mut Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))> =
                user_data as *const _ as usize
                    as *mut Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))>;
            if let Some(ref mut callback) = *callback {
                callback(&appinfo, pid)
            } else {
                panic!("cannot get closure...")
            };
        }
        let pid_callback = if pid_callback_data.is_some() {
            Some(pid_callback_func as _)
        } else {
            None
        };
        let super_callback0: Box_<Option<Box_<dyn FnOnce() + 'static>>> = user_setup_data;
        let super_callback1: &Option<&mut dyn (FnMut(&DesktopAppInfo, glib::Pid))> =
            &pid_callback_data;
        unsafe {
            let mut error = ptr::null_mut();
            let _ = ffi::g_desktop_app_info_launch_uris_as_manager_with_fds(
                self.as_ref().to_glib_none().0,
                uris.to_glib_none().0,
                launch_context.map(|p| p.as_ref()).to_glib_none().0,
                spawn_flags.into_glib(),
                user_setup,
                Box_::into_raw(super_callback0) as *mut _,
                pid_callback,
                super_callback1 as *const _ as usize as *mut _,
                stdin_fd.as_raw_fd(),
                stdout_fd.as_raw_fd(),
                stderr_fd.as_raw_fd(),
                &mut error,
            );
            if error.is_null() {
                Ok(())
            } else {
                Err(from_glib_full(error))
            }
        }
    }
}