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
172
173
174
175
176
177
178
179
180
181
//! Applet service.
//!
//! The APT service handles integration with other applications,
//! including high-level OS features such as Sleep mode, the Home Menu and application switching.
//!
//! It also handles running applets, small programs made available by the OS to streamline specific functionality.
//! Those are implemented in the [`applets`](crate::applets) module.

use crate::error::ResultCode;

/// Handle to the Applet service.
pub struct Apt(());

impl Apt {
    /// Initialize a new service handle.
    ///
    /// # Example
    ///
    /// ```
    /// # let _runner = test_runner::GdbRunner::default();
    /// # use std::error::Error;
    /// # fn main() -> Result<(), Box<dyn Error>> {
    /// #
    /// use ctru::services::apt::Apt;
    ///
    /// let apt = Apt::new()?;
    /// #
    /// # Ok(())
    /// # }
    /// ```
    #[doc(alias = "aptInit")]
    pub fn new() -> crate::Result<Apt> {
        unsafe {
            ResultCode(ctru_sys::aptInit())?;
            Ok(Apt(()))
        }
    }

    /// Returns `true` if the application is running in the foreground as normal.
    ///
    /// # Notes
    ///
    /// This function is called as such since it automatically handles all checks for Home Menu switching, Sleep mode and other events that could take away control from the application.
    /// For this reason, its main use is as the condition of a while loop that controls the main logic for your program.
    ///
    /// # Example
    ///
    /// ```
    /// # let _runner = test_runner::GdbRunner::default();
    /// use std::error::Error;
    /// use ctru::services::apt::Apt;
    ///
    /// // In a simple `main` function, the structure should be the following.
    /// fn main() -> Result<(), Box<dyn Error>> {
    ///
    /// let apt = Apt::new()?;
    ///
    /// while apt.main_loop() {
    ///     // Main program logic should be written here.
    /// }
    ///
    /// // Optional clean-ups after running the application should be written after the main loop.
    /// #
    /// # Ok(())
    /// # }
    /// ```
    #[doc(alias = "aptMainLoop")]
    pub fn main_loop(&self) -> bool {
        unsafe { ctru_sys::aptMainLoop() }
    }

    /// Set (in percentage) the amount of time to lend to the application thread spawned on the syscore (core #1).
    ///
    /// # Notes
    ///
    /// It is necessary to set a time limit before spawning threads on the syscore.
    /// The percentage value must be withing 5% and 89%, though it is suggested to use lower values (around 30-45%) to avoid slowing down the OS processes.
    #[doc(alias = "APT_SetAppCpuTimeLimit")]
    pub fn set_app_cpu_time_limit(&mut self, percent: u32) -> crate::Result<()> {
        unsafe {
            ResultCode(ctru_sys::APT_SetAppCpuTimeLimit(percent))?;
            Ok(())
        }
    }

    /// Set if the console is allowed to enter sleep mode.
    ///
    /// You can check whether the console is allowed to sleep with [Apt::is_sleep_allowed].
    #[doc(alias = "aptSetSleepAllowed")]
    pub fn set_sleep_allowed(&mut self, allowed: bool) {
        unsafe {
            ctru_sys::aptSetSleepAllowed(allowed);
        }
    }

    /// Check if the console is allowed to enter sleep mode.
    ///
    /// You can set whether the console is allowed to sleep with [Apt::set_sleep_allowed].
    #[doc(alias = "aptIsSleepAllowed")]
    pub fn is_sleep_allowed(&self) -> bool {
        unsafe { ctru_sys::aptIsSleepAllowed() }
    }

    /// Set if the console is allowed to enter the home menu.
    ///
    /// You can check whether the console is allowed to enter the home menu with [Apt::is_home_allowed].
    #[doc(alias = "aptSetHomeAllowed")]
    pub fn set_home_allowed(&mut self, allowed: bool) {
        unsafe {
            ctru_sys::aptSetHomeAllowed(allowed);
        }
    }

    /// Check if the console is allowed to enter the home menu.
    ///
    /// You can set whether the console is allowed to enter the home menu with [Apt::set_home_allowed].
    #[doc(alias = "aptIsHomeAllowed")]
    pub fn is_home_allowed(&self) -> bool {
        unsafe { ctru_sys::aptIsHomeAllowed() }
    }

    /// Immediately jumps to the home menu.
    #[doc(alias = "aptJumpToHomeMenu")]
    pub fn jump_to_home_menu(&mut self) {
        unsafe { ctru_sys::aptJumpToHomeMenu() }
    }
}

impl Drop for Apt {
    #[doc(alias = "aptExit")]
    fn drop(&mut self) {
        unsafe { ctru_sys::aptExit() };
    }
}

/// Can launch other applications when the current one exits.
pub struct Chainloader<'a> {
    _apt: &'a Apt,
}

impl<'a> Chainloader<'a> {
    /// Gets a handle to the chainloader
    pub fn new(apt: &'a Apt) -> Self {
        Self { _apt: apt }
    }

    /// Checks if the chainloader is set
    #[doc(alias = "aptIsChainload")]
    pub fn is_set(&self) -> bool {
        // static funtion not exported
        unsafe {
            (ctru_sys::envGetSystemRunFlags() & u32::from(ctru_sys::RUNFLAG_APTCHAINLOAD)) != 0
        }
    }

    /// Clears the chainloader state.
    #[doc(alias = "aptClearChainloader")]
    pub fn clear(&mut self) {
        unsafe { ctru_sys::aptClearChainloader() }
    }

    /// Configures the chainloader to launch a specific application.
    ///
    /// See also [`Title`](crate::services::am::Title]
    #[doc(alias = "aptSetChainloader")]
    pub fn set(&mut self, title: &super::am::Title<'_>) {
        unsafe { ctru_sys::aptSetChainloader(title.id(), title.media_type() as u8) }
    }

    /// Configures the chainloader to launch the previous application.
    #[doc(alias = "aptSetChainloaderToCaller")]
    pub fn set_to_caller(&mut self) {
        unsafe { ctru_sys::aptSetChainloaderToCaller() }
    }

    /// Configures the chainloader to relaunch the current application (i.e. soft-reset)
    #[doc(alias = "aptSetChainloaderToSelf")]
    pub fn set_to_self(&mut self) {
        unsafe { ctru_sys::aptSetChainloaderToSelf() }
    }
}