Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement low hanging apt sleep/homemenu functions and chainloader #161

Merged
merged 9 commits into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ctru-rs/src/services/am.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ impl<'a> Title<'a> {
pub fn version(&self) -> u16 {
self.version
}

/// Returns this title's media type
pub fn media_type(&self) -> MediaType {
self.mediatype
}
}

/// Handle to the Application Manager service.
Expand Down
87 changes: 87 additions & 0 deletions ctru-rs/src/services/apt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,48 @@ impl Apt {
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 {
Expand All @@ -90,3 +132,48 @@ impl Drop for Apt {
unsafe { ctru_sys::aptExit() };
}
}

/// Can launch other applications when the current one exits.
pub struct Chainloader<'a> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chainloader should clear on Drop, so that leftovers from previous usages won't influence in un-mutable environments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i did think about this, but then forgot to propose it.

the problem is that the destructor will run when you exit the app, as the chainloader goes out of scope.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right, didn’t think about it.

Wait, does this mean the setup only works because there is a reference to Apt that doesn’t get uninitialised? (The one made in libctru, i mean). If this were to not work without that (because the apt service were to be unused) then we must find a way around this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

at a first look it definitely looks that way.

_apt: &'a Apt,
}

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe Chainloader should require a mutable reference to Apt, but that may not be necessary if no other aspect of Apt reads or uses data handled by Chainloader.

Tell me what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i tried this, but then using it inside the main apt loop is a mess because it takes an immutable reference to loop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I know, that’s exactly what I was thinking would happen. It’s not an issue as long as all of the chainloader code is only accessible from here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these are the only chainloader functions, so i think it's fine to have it be this way

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() & 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() }
}
}
Loading