mirror of
https://gitlab.com/gabmus/envision.git
synced 2025-04-21 12:04:50 +00:00
feat: remove runtime switch; switch runtime on the fly on service start/stop
This commit is contained in:
parent
261703ae5a
commit
50cf3a4511
9 changed files with 124 additions and 203 deletions
|
@ -23,14 +23,21 @@ pub struct ActiveRuntime {
|
|||
pub runtime: ActiveRuntimeInnerRuntime,
|
||||
}
|
||||
|
||||
fn get_active_runtime_json_path() -> String {
|
||||
pub fn get_openxr_conf_dir() -> String {
|
||||
format!(
|
||||
"{config}/openxr/1/active_runtime.json",
|
||||
"{config}/openxr",
|
||||
config = get_xdg_config_dir()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_steam(active_runtime: ActiveRuntime) -> bool {
|
||||
fn get_active_runtime_json_path() -> String {
|
||||
format!(
|
||||
"{config}/1/active_runtime.json",
|
||||
config = get_openxr_conf_dir()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_steam(active_runtime: &ActiveRuntime) -> bool {
|
||||
match active_runtime.runtime.valve_runtime_is_steamvr {
|
||||
Some(true) => true,
|
||||
_ => false,
|
||||
|
@ -45,16 +52,16 @@ pub fn get_current_active_runtime() -> Option<ActiveRuntime> {
|
|||
get_active_runtime_from_path(&get_active_runtime_json_path())
|
||||
}
|
||||
|
||||
fn dump_active_runtime_to_path(active_runtime: ActiveRuntime, path_s: String) {
|
||||
set_file_radonly(&path_s, false);
|
||||
let writer = get_writer(&path_s);
|
||||
serde_json::to_writer_pretty(writer, &active_runtime)
|
||||
fn dump_active_runtime_to_path(active_runtime: &ActiveRuntime, path_s: &String) {
|
||||
set_file_radonly(path_s, false);
|
||||
let writer = get_writer(path_s);
|
||||
serde_json::to_writer_pretty(writer, active_runtime)
|
||||
.expect_dialog("Unable to save active runtime");
|
||||
set_file_radonly(&path_s, true);
|
||||
set_file_radonly(path_s, true);
|
||||
}
|
||||
|
||||
pub fn dump_current_active_runtime(active_runtime: ActiveRuntime) {
|
||||
dump_active_runtime_to_path(active_runtime, get_active_runtime_json_path());
|
||||
pub fn dump_current_active_runtime(active_runtime: &ActiveRuntime) {
|
||||
dump_active_runtime_to_path(active_runtime, &get_active_runtime_json_path());
|
||||
}
|
||||
|
||||
fn build_steam_active_runtime() -> ActiveRuntime {
|
||||
|
@ -72,10 +79,10 @@ fn build_steam_active_runtime() -> ActiveRuntime {
|
|||
}
|
||||
|
||||
pub fn set_current_active_runtime_to_steam() {
|
||||
dump_current_active_runtime(build_steam_active_runtime())
|
||||
dump_current_active_runtime(&build_steam_active_runtime())
|
||||
}
|
||||
|
||||
fn build_profile_active_runtime(profile: Profile) -> ActiveRuntime {
|
||||
pub fn build_profile_active_runtime(profile: &Profile) -> ActiveRuntime {
|
||||
ActiveRuntime {
|
||||
file_format_version: "1.0.0".into(),
|
||||
runtime: ActiveRuntimeInnerRuntime {
|
||||
|
@ -93,7 +100,7 @@ fn build_profile_active_runtime(profile: Profile) -> ActiveRuntime {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_current_active_runtime_to_profile(profile: Profile) {
|
||||
pub fn set_current_active_runtime_to_profile(profile: &Profile) {
|
||||
let pfx = profile.clone().prefix;
|
||||
let mut ar = build_profile_active_runtime(profile);
|
||||
// hack: relativize libopenxr_monado.so path for system installs
|
||||
|
@ -111,7 +118,7 @@ pub fn set_current_active_runtime_to_profile(profile: Profile) {
|
|||
rels = rel_chain.join("/")
|
||||
);
|
||||
}
|
||||
dump_current_active_runtime(ar);
|
||||
dump_current_active_runtime(&ar);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -146,6 +153,6 @@ mod tests {
|
|||
name: Some("SteamVR".into()),
|
||||
},
|
||||
};
|
||||
dump_active_runtime_to_path(ar, "./target/testout/active_runtime.json.steamvr".into());
|
||||
dump_active_runtime_to_path(&ar, &"./target/testout/active_runtime.json.steamvr".into());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,21 @@ pub struct OpenVrPaths {
|
|||
version: u32,
|
||||
}
|
||||
|
||||
fn get_openvrpaths_vrpath_path() -> String {
|
||||
pub fn get_openvr_conf_dir() -> String {
|
||||
format!(
|
||||
"{config}/openvr/openvrpaths.vrpath",
|
||||
"{config}/openvr",
|
||||
config = get_xdg_config_dir()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_steam(ovr_paths: OpenVrPaths) -> bool {
|
||||
fn get_openvrpaths_vrpath_path() -> String {
|
||||
format!(
|
||||
"{config}/openvrpaths.vrpath",
|
||||
config = get_openvr_conf_dir()
|
||||
)
|
||||
}
|
||||
|
||||
pub fn is_steam(ovr_paths: &OpenVrPaths) -> bool {
|
||||
ovr_paths
|
||||
.runtime
|
||||
.iter()
|
||||
|
@ -43,15 +50,15 @@ pub fn get_current_openvrpaths() -> Option<OpenVrPaths> {
|
|||
get_openvrpaths_from_path(&get_openvrpaths_vrpath_path())
|
||||
}
|
||||
|
||||
fn dump_openvrpaths_to_path(ovr_paths: OpenVrPaths, path_s: String) {
|
||||
set_file_radonly(&path_s, false);
|
||||
let writer = get_writer(&path_s);
|
||||
serde_json::to_writer_pretty(writer, &ovr_paths).expect_dialog("Unable to save openvrpaths");
|
||||
set_file_radonly(&path_s, true);
|
||||
fn dump_openvrpaths_to_path(ovr_paths: &OpenVrPaths, path_s: &String) {
|
||||
set_file_radonly(path_s, false);
|
||||
let writer = get_writer(path_s);
|
||||
serde_json::to_writer_pretty(writer, ovr_paths).expect_dialog("Unable to save openvrpaths");
|
||||
set_file_radonly(path_s, true);
|
||||
}
|
||||
|
||||
pub fn dump_current_openvrpaths(ovr_paths: OpenVrPaths) {
|
||||
dump_openvrpaths_to_path(ovr_paths, get_openvrpaths_vrpath_path())
|
||||
pub fn dump_current_openvrpaths(ovr_paths: &OpenVrPaths) {
|
||||
dump_openvrpaths_to_path(ovr_paths, &get_openvrpaths_vrpath_path())
|
||||
}
|
||||
|
||||
fn build_steam_openvrpaths() -> OpenVrPaths {
|
||||
|
@ -70,10 +77,10 @@ fn build_steam_openvrpaths() -> OpenVrPaths {
|
|||
}
|
||||
|
||||
pub fn set_current_openvrpaths_to_steam() {
|
||||
dump_current_openvrpaths(build_steam_openvrpaths())
|
||||
dump_current_openvrpaths(&build_steam_openvrpaths())
|
||||
}
|
||||
|
||||
fn build_profile_openvrpaths(profile: Profile) -> OpenVrPaths {
|
||||
pub fn build_profile_openvrpaths(profile: &Profile) -> OpenVrPaths {
|
||||
let datadir = get_xdg_data_dir();
|
||||
OpenVrPaths {
|
||||
config: vec![format!("{data}/Steam/config", data = datadir)],
|
||||
|
@ -88,8 +95,8 @@ fn build_profile_openvrpaths(profile: Profile) -> OpenVrPaths {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_current_openvrpaths_to_profile(profile: Profile) {
|
||||
dump_current_openvrpaths(build_profile_openvrpaths(profile))
|
||||
pub fn set_current_openvrpaths_to_profile(profile: &Profile) {
|
||||
dump_current_openvrpaths(&build_profile_openvrpaths(profile))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -119,6 +126,6 @@ mod tests {
|
|||
runtime: vec!["/home/user/.local/share/Steam/steamapps/common/SteamVR".into()],
|
||||
version: 1,
|
||||
};
|
||||
dump_openvrpaths_to_path(ovrp, "./target/testout/openvrpaths.vrpath".into())
|
||||
dump_openvrpaths_to_path(&ovrp, &"./target/testout/openvrpaths.vrpath".into())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::{constants::CMD_NAME, runner::Runner};
|
|||
use expect_dialog::ExpectDialog;
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, create_dir_all, File, OpenOptions},
|
||||
fs::{self, create_dir_all, remove_dir_all, File, OpenOptions},
|
||||
io::{BufReader, BufWriter},
|
||||
path::Path,
|
||||
};
|
||||
|
@ -78,6 +78,10 @@ pub fn get_xdg_cache_dir() -> String {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn get_xdg_runtime_dir() -> String {
|
||||
env::var("XDG_RUNTIME_DIR").expect_dialog("XDG_RUNTIME_DIR is not set")
|
||||
}
|
||||
|
||||
pub fn get_config_dir() -> String {
|
||||
format!(
|
||||
"{config}/{name}",
|
||||
|
@ -137,3 +141,10 @@ pub fn get_exec_prefix() -> String {
|
|||
.unwrap()
|
||||
.to_string()
|
||||
}
|
||||
|
||||
pub fn rm_rf(path_s: &String) {
|
||||
match remove_dir_all(path_s) {
|
||||
Err(_) => println!("Failed to remove path {}", path_s),
|
||||
Ok(_) => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -173,27 +173,32 @@ impl Default for Profile {
|
|||
|
||||
impl Profile {
|
||||
pub fn get_steam_launch_options(&self) -> String {
|
||||
let mut opts = vec![];
|
||||
opts.push(format!(
|
||||
"XR_RUNTIME_JSON={prefix}/share/openxr/1/openxr_{runtime}.json",
|
||||
prefix = match self.prefix.as_str() {
|
||||
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
|
||||
other => other,
|
||||
},
|
||||
runtime = match self.xrservice_type {
|
||||
XRServiceType::Monado => "monado",
|
||||
XRServiceType::Wivrn => "wivrn",
|
||||
}
|
||||
));
|
||||
opts.push(format!(
|
||||
"PRESSURE_VESSEL_FILESYSTEMS_RW=$XDG_RUNTIME_DIR/{xrservice}_comp_ipc",
|
||||
xrservice = match self.xrservice_type {
|
||||
XRServiceType::Monado => "monado",
|
||||
XRServiceType::Wivrn => "wivrn",
|
||||
}
|
||||
));
|
||||
opts.push("%command%".into());
|
||||
opts.join(" ")
|
||||
vec![
|
||||
format!(
|
||||
"VR_OVERRIDE={opencomp}/build",
|
||||
opencomp = self.opencomposite_path,
|
||||
),
|
||||
format!(
|
||||
"XR_RUNTIME_JSON={prefix}/share/openxr/1/openxr_{runtime}.json",
|
||||
prefix = match self.prefix.as_str() {
|
||||
SYSTEM_PREFIX => BWRAP_SYSTEM_PREFIX,
|
||||
other => other,
|
||||
},
|
||||
runtime = match self.xrservice_type {
|
||||
XRServiceType::Monado => "monado",
|
||||
XRServiceType::Wivrn => "wivrn",
|
||||
}
|
||||
),
|
||||
format!(
|
||||
"PRESSURE_VESSEL_FILESYSTEMS_RW=$XDG_RUNTIME_DIR/{xrservice}_comp_ipc",
|
||||
xrservice = match self.xrservice_type {
|
||||
XRServiceType::Monado => "monado",
|
||||
XRServiceType::Wivrn => "wivrn",
|
||||
}
|
||||
),
|
||||
"%command%".into(),
|
||||
]
|
||||
.join(" ")
|
||||
}
|
||||
|
||||
pub fn load_profile(path: &String) -> Self {
|
||||
|
|
|
@ -18,6 +18,8 @@ use crate::dependencies::mercury_deps::get_missing_mercury_deps;
|
|||
use crate::dependencies::monado_deps::get_missing_monado_deps;
|
||||
use crate::dependencies::pkexec_dep::pkexec_dep;
|
||||
use crate::dependencies::wivrn_deps::get_missing_wivrn_deps;
|
||||
use crate::file_builders::active_runtime_json::{set_current_active_runtime_to_profile, set_current_active_runtime_to_steam};
|
||||
use crate::file_builders::openvrpaths_vrpath::{set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam};
|
||||
use crate::file_utils::setcap_cap_sys_nice_eip;
|
||||
use crate::log_parser::MonadoLog;
|
||||
use crate::profile::{Profile, XRServiceType};
|
||||
|
@ -94,7 +96,6 @@ pub enum Msg {
|
|||
OpenLibsurviveSetup,
|
||||
Quit,
|
||||
ProcessDevicesLog(Vec<String>),
|
||||
InhibitSession(bool),
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -134,6 +135,8 @@ impl App {
|
|||
pub fn start_xrservice(&mut self) {
|
||||
self.set_inhibit_session(true);
|
||||
let prof = self.get_selected_profile();
|
||||
set_current_active_runtime_to_profile(&prof);
|
||||
set_current_openvrpaths_to_profile(&prof);
|
||||
self.devices_processed = match prof.xrservice_type {
|
||||
XRServiceType::Monado => false,
|
||||
XRServiceType::Wivrn => true, // no device from log in wivrn
|
||||
|
@ -156,6 +159,20 @@ impl App {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn shutdown_xrservice(&mut self) {
|
||||
if self.xrservice_runner.is_some() {
|
||||
if self.xrservice_runner.as_mut().unwrap().status() == RunnerStatus::Running {
|
||||
self.xrservice_runner.as_mut().unwrap().terminate();
|
||||
}
|
||||
}
|
||||
set_current_active_runtime_to_steam();
|
||||
set_current_openvrpaths_to_steam();
|
||||
self.set_inhibit_session(false);
|
||||
self.main_view
|
||||
.sender()
|
||||
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
||||
}
|
||||
|
||||
pub fn profiles_list(config: &Config) -> Vec<Profile> {
|
||||
let mut profiles = vec![
|
||||
valve_index_profile(),
|
||||
|
@ -200,17 +217,18 @@ impl SimpleComponent for App {
|
|||
},
|
||||
model.debug_view.widget(),
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn shutdown(&mut self, widgets: &mut Self::Widgets, output: relm4::Sender<Self::Output>) {
|
||||
match &mut self.xrservice_runner {
|
||||
None => {}
|
||||
Some(runner) => {
|
||||
runner.terminate();
|
||||
if self.xrservice_runner.is_some() {
|
||||
if self.xrservice_runner.as_mut().unwrap().status() == RunnerStatus::Running {
|
||||
self.xrservice_runner.as_mut().unwrap().terminate();
|
||||
}
|
||||
}
|
||||
set_current_active_runtime_to_steam();
|
||||
set_current_openvrpaths_to_steam();
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||
|
@ -320,18 +338,13 @@ impl SimpleComponent for App {
|
|||
}
|
||||
Some(runner) => match runner.status() {
|
||||
RunnerStatus::Running => {
|
||||
sender.input(Msg::InhibitSession(false));
|
||||
runner.terminate();
|
||||
self.main_view
|
||||
.sender()
|
||||
.emit(MainViewMsg::XRServiceActiveChanged(false, None));
|
||||
self.shutdown_xrservice();
|
||||
}
|
||||
RunnerStatus::Stopped(_) => {
|
||||
self.start_xrservice();
|
||||
}
|
||||
},
|
||||
},
|
||||
Msg::InhibitSession(state) => self.set_inhibit_session(state),
|
||||
Msg::BuildProfile => {
|
||||
let profile = self.get_selected_profile();
|
||||
let mut missing_deps = vec![];
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
use super::devices_box::{DevicesBox, DevicesBoxMsg};
|
||||
use super::install_wivrn_box::{InstallWivrnBox, InstallWivrnBoxInit, InstallWivrnBoxMsg};
|
||||
use super::profile_editor::{ProfileEditor, ProfileEditorMsg, ProfileEditorOutMsg};
|
||||
use super::runtime_switcher_box::{
|
||||
RuntimeSwitcherBox, RuntimeSwitcherBoxInit, RuntimeSwitcherBoxMsg,
|
||||
};
|
||||
use super::steam_launch_options_box::{SteamLaunchOptionsBox, SteamLaunchOptionsBoxMsg};
|
||||
use crate::config::Config;
|
||||
use crate::constants::APP_NAME;
|
||||
|
@ -32,8 +29,6 @@ pub struct MainView {
|
|||
#[tracker::do_not_track]
|
||||
steam_launch_options_box: Controller<SteamLaunchOptionsBox>,
|
||||
#[tracker::do_not_track]
|
||||
runtime_switcher_box: Controller<RuntimeSwitcherBox>,
|
||||
#[tracker::do_not_track]
|
||||
devices_box: Controller<DevicesBox>,
|
||||
#[tracker::do_not_track]
|
||||
profile_editor: Controller<ProfileEditor>,
|
||||
|
@ -147,7 +142,6 @@ impl SimpleComponent for MainView {
|
|||
},
|
||||
},
|
||||
model.devices_box.widget(),
|
||||
model.runtime_switcher_box.widget(),
|
||||
model.steam_launch_options_box.widget(),
|
||||
model.install_wivrn_box.widget(),
|
||||
}
|
||||
|
@ -250,9 +244,6 @@ impl SimpleComponent for MainView {
|
|||
self.install_wivrn_box
|
||||
.sender()
|
||||
.emit(InstallWivrnBoxMsg::UpdateSelectedProfile(prof.clone()));
|
||||
self.runtime_switcher_box
|
||||
.sender()
|
||||
.emit(RuntimeSwitcherBoxMsg::UpdateSelectedProfile(prof.clone()));
|
||||
}
|
||||
Self::Input::UpdateProfiles(profiles, config) => {
|
||||
self.set_profiles(profiles);
|
||||
|
@ -376,11 +367,6 @@ impl SimpleComponent for MainView {
|
|||
root_win: init.root_win.clone(),
|
||||
})
|
||||
.detach(),
|
||||
runtime_switcher_box: RuntimeSwitcherBox::builder()
|
||||
.launch(RuntimeSwitcherBoxInit {
|
||||
selected_profile: init.selected_profile.clone(),
|
||||
})
|
||||
.detach(),
|
||||
profile_editor: ProfileEditor::builder()
|
||||
.launch(ProfileEditorInit {
|
||||
root_win: init.root_win.clone(),
|
||||
|
|
|
@ -6,7 +6,6 @@ pub mod build_window;
|
|||
pub mod libsurvive_setup_window;
|
||||
pub mod install_wivrn_box;
|
||||
pub mod steam_launch_options_box;
|
||||
pub mod runtime_switcher_box;
|
||||
pub mod profile_editor;
|
||||
pub mod factories;
|
||||
pub mod wivrn_conf_editor;
|
||||
|
|
|
@ -1,109 +0,0 @@
|
|||
use relm4::prelude::*;
|
||||
use gtk::prelude::*;
|
||||
use crate::{constants::APP_NAME, file_builders::{active_runtime_json::{get_current_active_runtime, self, set_current_active_runtime_to_profile, set_current_active_runtime_to_steam}, openvrpaths_vrpath::{set_current_openvrpaths_to_profile, set_current_openvrpaths_to_steam}}, profile::Profile};
|
||||
|
||||
pub struct RuntimeSwitcherBox {
|
||||
selected_profile: Profile,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RuntimeSwitcherBoxMsg {
|
||||
UpdateSelectedProfile(Profile),
|
||||
SetXRServiceRuntime(bool),
|
||||
}
|
||||
|
||||
pub struct RuntimeSwitcherBoxInit {
|
||||
pub selected_profile: Profile,
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl SimpleComponent for RuntimeSwitcherBox {
|
||||
type Init = RuntimeSwitcherBoxInit;
|
||||
type Input = RuntimeSwitcherBoxMsg;
|
||||
type Output = ();
|
||||
|
||||
view! {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_hexpand: true,
|
||||
set_spacing: 12,
|
||||
gtk::Separator {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
},
|
||||
gtk::Label {
|
||||
add_css_class: "heading",
|
||||
set_hexpand: true,
|
||||
set_xalign: 0.0,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
set_label: "OpenXR/OpenVR Runtime",
|
||||
set_wrap: true,
|
||||
set_wrap_mode: gtk::pango::WrapMode::Word,
|
||||
},
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_hexpand: true,
|
||||
set_halign: gtk::Align::Start,
|
||||
set_margin_start: 12,
|
||||
set_margin_end: 12,
|
||||
set_spacing: 12,
|
||||
gtk::Label {
|
||||
set_label: "Steam",
|
||||
},
|
||||
#[name(runtime_switch)]
|
||||
gtk::Switch {
|
||||
},
|
||||
gtk::Label {
|
||||
set_label: APP_NAME,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||
match message {
|
||||
Self::Input::UpdateSelectedProfile(prof) => {
|
||||
self.selected_profile = prof;
|
||||
}
|
||||
Self::Input::SetXRServiceRuntime(is_rex) => {
|
||||
if is_rex {
|
||||
set_current_active_runtime_to_profile(self.selected_profile.clone());
|
||||
set_current_openvrpaths_to_profile(self.selected_profile.clone());
|
||||
} else {
|
||||
set_current_active_runtime_to_steam();
|
||||
set_current_openvrpaths_to_steam();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
init: Self::Init,
|
||||
root: &Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let model = Self {
|
||||
selected_profile: init.selected_profile,
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
{
|
||||
match get_current_active_runtime() {
|
||||
None => {}
|
||||
Some(runtime) => {
|
||||
widgets
|
||||
.runtime_switch
|
||||
.set_active(!active_runtime_json::is_steam(runtime));
|
||||
}
|
||||
}
|
||||
widgets.runtime_switch.connect_state_set(move |_, state| {
|
||||
sender.input(Self::Input::SetXRServiceRuntime(state));
|
||||
gtk::Inhibit(false)
|
||||
});
|
||||
}
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
}
|
|
@ -64,22 +64,24 @@ impl SimpleComponent for SteamLaunchOptionsBox {
|
|||
set_margin_end: 12,
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 6,
|
||||
gtk::TextView {
|
||||
gtk::ScrolledWindow {
|
||||
add_css_class: "card",
|
||||
set_hexpand: true,
|
||||
set_vexpand: false,
|
||||
set_monospace: true,
|
||||
set_editable: false,
|
||||
set_wrap_mode: gtk::WrapMode::Word,
|
||||
set_left_margin: 6,
|
||||
set_right_margin: 6,
|
||||
set_top_margin: 6,
|
||||
set_bottom_margin: 6,
|
||||
set_size_request: (-1, 150),
|
||||
#[wrap(Some)]
|
||||
set_buffer: cmdbuf = >k::TextBuffer {
|
||||
#[track = "model.changed(Self::launch_options())"]
|
||||
set_text: model.launch_options.as_str(),
|
||||
set_vscrollbar_policy: gtk::PolicyType::Never,
|
||||
set_overflow: gtk::Overflow::Hidden,
|
||||
gtk::TextView {
|
||||
set_hexpand: true,
|
||||
set_vexpand: false,
|
||||
set_monospace: true,
|
||||
set_editable: false,
|
||||
set_left_margin: 6,
|
||||
set_right_margin: 6,
|
||||
set_top_margin: 6,
|
||||
set_bottom_margin: 18,
|
||||
#[wrap(Some)]
|
||||
set_buffer: cmdbuf = >k::TextBuffer {
|
||||
#[track = "model.changed(Self::launch_options())"]
|
||||
set_text: model.launch_options.as_str(),
|
||||
}
|
||||
}
|
||||
},
|
||||
gtk::Button {
|
||||
|
|
Loading…
Add table
Reference in a new issue