mirror of
https://github.com/an-anime-team/sleepy-launcher.git
synced 2025-03-15 06:28:27 +03:00
feat: added game sandboxing
This commit is contained in:
parent
07a992be58
commit
d058342829
4 changed files with 226 additions and 3 deletions
|
@ -128,6 +128,7 @@ impl SimpleAsyncComponent for EnvironmentApp {
|
|||
|
||||
gtk::Button {
|
||||
set_label: &tr("add"),
|
||||
add_css_class: "pill",
|
||||
|
||||
set_margin_top: 8,
|
||||
set_halign: gtk::Align::Start,
|
||||
|
@ -176,11 +177,13 @@ impl SimpleAsyncComponent for EnvironmentApp {
|
|||
let name = self.name.text().trim().to_string();
|
||||
let value = self.value.text().trim().to_string();
|
||||
|
||||
config.game.environment.insert(name.clone(), value.clone());
|
||||
if !name.is_empty() && !value.is_empty() {
|
||||
config.game.environment.insert(name.clone(), value.clone());
|
||||
|
||||
Config::update(config);
|
||||
Config::update(config);
|
||||
|
||||
self.variables.guard().push_back((name, value));
|
||||
self.variables.guard().push_back((name, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ use crate::i18n::tr;
|
|||
|
||||
use super::general::*;
|
||||
use super::enhancements::*;
|
||||
use super::sandbox::*;
|
||||
use super::environment::*;
|
||||
|
||||
pub static mut PREFERENCES_WINDOW: Option<adw::PreferencesWindow> = None;
|
||||
|
@ -22,6 +23,7 @@ pub static mut PREFERENCES_WINDOW: Option<adw::PreferencesWindow> = None;
|
|||
pub struct PreferencesApp {
|
||||
general: AsyncController<GeneralApp>,
|
||||
enhancements: AsyncController<EnhancementsApp>,
|
||||
sandbox: AsyncController<SandboxApp>,
|
||||
environment: AsyncController<EnvironmentApp>
|
||||
}
|
||||
|
||||
|
@ -67,6 +69,7 @@ impl SimpleAsyncComponent for PreferencesApp {
|
|||
|
||||
add = model.general.widget(),
|
||||
add = model.enhancements.widget(),
|
||||
add = model.sandbox.widget(),
|
||||
add = model.environment.widget(),
|
||||
|
||||
connect_close_request[sender] => move |_| {
|
||||
|
@ -98,6 +101,10 @@ impl SimpleAsyncComponent for PreferencesApp {
|
|||
.launch(())
|
||||
.detach(),
|
||||
|
||||
sandbox: SandboxApp::builder()
|
||||
.launch(())
|
||||
.detach(),
|
||||
|
||||
environment: EnvironmentApp::builder()
|
||||
.launch(())
|
||||
.detach()
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
pub mod main;
|
||||
pub mod general;
|
||||
pub mod enhancements;
|
||||
pub mod sandbox;
|
||||
pub mod environment;
|
||||
pub mod gamescope;
|
||||
|
|
212
src/ui/preferences/sandbox.rs
Normal file
212
src/ui/preferences/sandbox.rs
Normal file
|
@ -0,0 +1,212 @@
|
|||
use relm4::prelude::*;
|
||||
use relm4::component::*;
|
||||
use relm4::factory::*;
|
||||
|
||||
use adw::prelude::*;
|
||||
|
||||
use anime_launcher_sdk::is_available;
|
||||
|
||||
use crate::i18n::tr;
|
||||
use crate::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Directory {
|
||||
path: String
|
||||
}
|
||||
|
||||
#[relm4::factory(async)]
|
||||
impl AsyncFactoryComponent for Directory {
|
||||
type Init = String;
|
||||
type Input = SandboxAppMsg;
|
||||
type Output = SandboxAppMsg;
|
||||
type CommandOutput = ();
|
||||
type ParentInput = SandboxAppMsg;
|
||||
type ParentWidget = adw::PreferencesGroup;
|
||||
|
||||
view! {
|
||||
root = adw::ActionRow {
|
||||
set_title: &self.path,
|
||||
|
||||
add_suffix = >k::Button {
|
||||
set_icon_name: "user-trash-symbolic",
|
||||
add_css_class: "flat",
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
connect_clicked[sender, index] => move |_| {
|
||||
sender.input(SandboxAppMsg::Remove(index.clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn output_to_parent_input(output: Self::Output) -> Option<Self::ParentInput> {
|
||||
Some(output)
|
||||
}
|
||||
|
||||
async fn init_model(
|
||||
init: Self::Init,
|
||||
_index: &DynamicIndex,
|
||||
_sender: AsyncFactorySender<Self>,
|
||||
) -> Self {
|
||||
Self {
|
||||
path: init
|
||||
}
|
||||
}
|
||||
|
||||
async fn update(&mut self, msg: Self::Input, sender: AsyncFactorySender<Self>) {
|
||||
sender.output(msg);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SandboxApp {
|
||||
directories: AsyncFactoryVecDeque<Directory>,
|
||||
|
||||
sandboxing_path: adw::EntryRow
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum SandboxAppMsg {
|
||||
Add,
|
||||
Remove(DynamicIndex)
|
||||
}
|
||||
|
||||
#[relm4::component(async, pub)]
|
||||
impl SimpleAsyncComponent for SandboxApp {
|
||||
type Init = ();
|
||||
type Input = SandboxAppMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
adw::PreferencesPage {
|
||||
set_title: "Sandbox",
|
||||
set_icon_name: Some("folder-symbolic"),
|
||||
|
||||
set_sensitive: is_available("bwrap"),
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
set_title: "Sandbox",
|
||||
set_description: Some("Run the game in isolated environment, preventing it from accessing your personal data"),
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: "Enable sandboxing",
|
||||
set_subtitle: "Run the game in read-only copy of your root filesystem",
|
||||
|
||||
add_suffix = >k::Switch {
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
set_state: CONFIG.sandbox.enabled,
|
||||
|
||||
connect_state_notify => |switch| {
|
||||
if is_ready() {
|
||||
if let Ok(mut config) = Config::get() {
|
||||
config.sandbox.enabled = switch.state();
|
||||
|
||||
Config::update(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
adw::ActionRow {
|
||||
set_title: "Hide home directory",
|
||||
set_subtitle: "Isolate your /home, /var/home/{username}, and $HOME folders from the game",
|
||||
|
||||
add_suffix = >k::Switch {
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
set_state: CONFIG.sandbox.isolate_home,
|
||||
|
||||
connect_state_notify => |switch| {
|
||||
if is_ready() {
|
||||
if let Ok(mut config) = Config::get() {
|
||||
config.sandbox.isolate_home = switch.state();
|
||||
|
||||
Config::update(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
add = &adw::PreferencesGroup {
|
||||
set_title: "Sandboxed directories",
|
||||
set_description: Some("These folders will be replaced by in-memory filesystem (tmpfs), and their original content will not be available to sandboxed game"),
|
||||
|
||||
#[local_ref]
|
||||
sandboxing_path -> adw::EntryRow {
|
||||
set_title: "Path"
|
||||
},
|
||||
|
||||
gtk::Button {
|
||||
set_label: &tr("add"),
|
||||
add_css_class: "pill",
|
||||
|
||||
set_margin_top: 8,
|
||||
set_halign: gtk::Align::Start,
|
||||
|
||||
connect_clicked => SandboxAppMsg::Add
|
||||
}
|
||||
},
|
||||
|
||||
#[local_ref]
|
||||
add = directories -> adw::PreferencesGroup {}
|
||||
}
|
||||
}
|
||||
|
||||
async fn init(
|
||||
_init: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: AsyncComponentSender<Self>,
|
||||
) -> AsyncComponentParts<Self> {
|
||||
tracing::info!("Initializing environment settings");
|
||||
|
||||
let mut model = Self {
|
||||
directories: AsyncFactoryVecDeque::new(adw::PreferencesGroup::new(), sender.input_sender()),
|
||||
|
||||
sandboxing_path: adw::EntryRow::new()
|
||||
};
|
||||
|
||||
for path in &CONFIG.sandbox.private {
|
||||
model.directories.guard().push_back(path.trim().to_string());
|
||||
}
|
||||
|
||||
let directories = model.directories.widget();
|
||||
let sandboxing_path = &model.sandboxing_path;
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
AsyncComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender<Self>) {
|
||||
match msg {
|
||||
SandboxAppMsg::Add => {
|
||||
if let Ok(mut config) = Config::get() {
|
||||
let path = self.sandboxing_path.text().trim().to_string();
|
||||
|
||||
if !path.is_empty() {
|
||||
config.sandbox.private.push(path.clone());
|
||||
|
||||
Config::update(config);
|
||||
|
||||
self.directories.guard().push_back(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SandboxAppMsg::Remove(index) => {
|
||||
if let Ok(mut config) = Config::get() {
|
||||
if let Some(var) = self.directories.guard().get(index.current_index()) {
|
||||
config.sandbox.private.retain(|item| item != &var.path);
|
||||
|
||||
Config::update(config);
|
||||
}
|
||||
|
||||
self.directories.guard().remove(index.current_index());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue