Skip to main content

gio/
application.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, ops::ControlFlow};
4
5use glib::{
6    ExitCode, GString,
7    prelude::*,
8    signal::{SignalHandlerId, connect_raw},
9    translate::*,
10};
11
12use crate::{Application, ApplicationCommandLine, File, ffi};
13
14pub trait ApplicationExtManual: IsA<Application> {
15    #[doc(alias = "g_application_run")]
16    fn run(&self) -> ExitCode {
17        self.run_with_args(&std::env::args().collect::<Vec<_>>())
18    }
19
20    #[doc(alias = "g_application_run")]
21    fn run_with_args<S: AsRef<str>>(&self, args: &[S]) -> ExitCode {
22        let argv: Vec<&str> = args.iter().map(|a| a.as_ref()).collect();
23        let argc = argv.len() as i32;
24        let exit_code = unsafe {
25            ffi::g_application_run(self.as_ref().to_glib_none().0, argc, argv.to_glib_none().0)
26        };
27        ExitCode::try_from(exit_code).unwrap()
28    }
29
30    #[doc(alias = "open")]
31    fn connect_open<F: Fn(&Self, &[File], &str) + 'static>(&self, f: F) -> SignalHandlerId {
32        unsafe extern "C" fn open_trampoline<P, F: Fn(&P, &[File], &str) + 'static>(
33            this: *mut ffi::GApplication,
34            files: *const *mut ffi::GFile,
35            n_files: libc::c_int,
36            hint: *mut libc::c_char,
37            f: glib::ffi::gpointer,
38        ) where
39            P: IsA<Application>,
40        {
41            unsafe {
42                let f: &F = &*(f as *const F);
43                let files: Vec<File> =
44                    FromGlibContainer::from_glib_none_num(files, n_files as usize);
45                f(
46                    Application::from_glib_borrow(this).unsafe_cast_ref(),
47                    &files,
48                    &GString::from_glib_borrow(hint),
49                )
50            }
51        }
52        unsafe {
53            let f: Box_<F> = Box_::new(f);
54            connect_raw(
55                self.as_ptr() as *mut _,
56                b"open\0".as_ptr() as *const _,
57                Some(transmute::<*const (), unsafe extern "C" fn()>(
58                    open_trampoline::<Self, F> as *const (),
59                )),
60                Box_::into_raw(f),
61            )
62        }
63    }
64
65    #[doc(alias = "command-line")]
66    fn connect_command_line<F: Fn(&Self, &ApplicationCommandLine) -> ExitCode + 'static>(
67        &self,
68        f: F,
69    ) -> SignalHandlerId {
70        unsafe extern "C" fn command_line_trampoline<
71            P: IsA<Application>,
72            F: Fn(&P, &ApplicationCommandLine) -> ExitCode + 'static,
73        >(
74            this: *mut ffi::GApplication,
75            command_line: *mut ffi::GApplicationCommandLine,
76            f: glib::ffi::gpointer,
77        ) -> std::ffi::c_int {
78            unsafe {
79                let f: &F = &*(f as *const F);
80                f(
81                    Application::from_glib_borrow(this).unsafe_cast_ref(),
82                    &from_glib_borrow(command_line),
83                )
84                .into()
85            }
86        }
87        unsafe {
88            let f: Box_<F> = Box_::new(f);
89            connect_raw(
90                self.as_ptr() as *mut _,
91                c"command-line".as_ptr() as *const _,
92                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
93                    command_line_trampoline::<Self, F> as *const (),
94                )),
95                Box_::into_raw(f),
96            )
97        }
98    }
99
100    #[doc(alias = "handle-local-options")]
101    fn connect_handle_local_options<
102        F: Fn(&Self, &glib::VariantDict) -> ControlFlow<ExitCode> + 'static,
103    >(
104        &self,
105        f: F,
106    ) -> SignalHandlerId {
107        unsafe extern "C" fn handle_local_options_trampoline<
108            P: IsA<Application>,
109            F: Fn(&P, &glib::VariantDict) -> ControlFlow<ExitCode> + 'static,
110        >(
111            this: *mut ffi::GApplication,
112            options: *mut glib::ffi::GVariantDict,
113            f: glib::ffi::gpointer,
114        ) -> std::ffi::c_int {
115            unsafe {
116                let f: &F = &*(f as *const F);
117                f(
118                    Application::from_glib_borrow(this).unsafe_cast_ref(),
119                    &from_glib_borrow(options),
120                )
121                .break_value()
122                .map(i32::from)
123                .unwrap_or(-1)
124            }
125        }
126        unsafe {
127            let f: Box_<F> = Box_::new(f);
128            connect_raw(
129                self.as_ptr() as *mut _,
130                c"handle-local-options".as_ptr() as *const _,
131                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
132                    handle_local_options_trampoline::<Self, F> as *const (),
133                )),
134                Box_::into_raw(f),
135            )
136        }
137    }
138
139    #[doc(alias = "g_application_hold")]
140    fn hold(&self) -> ApplicationHoldGuard {
141        unsafe {
142            ffi::g_application_hold(self.as_ref().to_glib_none().0);
143        }
144        ApplicationHoldGuard(self.as_ref().downgrade())
145    }
146
147    #[doc(alias = "g_application_mark_busy")]
148    fn mark_busy(&self) -> ApplicationBusyGuard {
149        unsafe {
150            ffi::g_application_mark_busy(self.as_ref().to_glib_none().0);
151        }
152        ApplicationBusyGuard(self.as_ref().downgrade())
153    }
154}
155
156impl<O: IsA<Application>> ApplicationExtManual for O {}
157
158#[derive(Debug)]
159#[must_use = "if unused the Application will immediately be released"]
160pub struct ApplicationHoldGuard(glib::WeakRef<Application>);
161
162impl Drop for ApplicationHoldGuard {
163    #[inline]
164    fn drop(&mut self) {
165        if let Some(application) = self.0.upgrade() {
166            unsafe {
167                ffi::g_application_release(application.to_glib_none().0);
168            }
169        }
170    }
171}
172
173#[derive(Debug)]
174#[must_use = "if unused the Application will immediately be unmarked busy"]
175pub struct ApplicationBusyGuard(glib::WeakRef<Application>);
176
177impl Drop for ApplicationBusyGuard {
178    #[inline]
179    fn drop(&mut self) {
180        if let Some(application) = self.0.upgrade() {
181            unsafe {
182                ffi::g_application_unmark_busy(application.to_glib_none().0);
183            }
184        }
185    }
186}