Merge branch 'imbris/voxygen-settings-improvements' into 'master'

Cleanup things in voxygen settings, making the directory externally specified, removing unused and planned to be removed things

Closes #853

See merge request veloren/veloren!2645
This commit is contained in:
Imbris 2021-07-19 15:06:52 +00:00
commit b8b27cb5f7
12 changed files with 111 additions and 240 deletions

View File

@ -3436,12 +3436,16 @@ impl Hud {
.clamped(1.25, max_zoom / 64.0); .clamped(1.25, max_zoom / 64.0);
global_state.settings.interface.map_zoom = new_zoom_lvl; global_state.settings.interface.map_zoom = new_zoom_lvl;
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
} else if global_state.settings.interface.minimap_show { } else if global_state.settings.interface.minimap_show {
let new_zoom_lvl = global_state.settings.interface.minimap_zoom * factor; let new_zoom_lvl = global_state.settings.interface.minimap_zoom * factor;
global_state.settings.interface.minimap_zoom = new_zoom_lvl; global_state.settings.interface.minimap_zoom = new_zoom_lvl;
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
} }
show.map && global_state.settings.interface.minimap_show show.map && global_state.settings.interface.minimap_show

View File

@ -50,9 +50,12 @@ use crate::{
use common::clock::Clock; use common::clock::Clock;
use common_base::span; use common_base::span;
use i18n::LocalizationHandle; use i18n::LocalizationHandle;
use std::path::PathBuf;
/// A type used to store state that is shared between all play states. /// A type used to store state that is shared between all play states.
pub struct GlobalState { pub struct GlobalState {
pub userdata_dir: PathBuf,
pub config_dir: PathBuf,
pub settings: Settings, pub settings: Settings,
pub profile: Profile, pub profile: Profile,
pub window: Window, pub window: Window,

View File

@ -17,33 +17,54 @@ use veloren_voxygen::{
#[cfg(feature = "hot-reloading")] #[cfg(feature = "hot-reloading")]
use common::assets; use common::assets;
use common::clock::Clock; use common::clock::Clock;
use std::panic; use std::{panic, path::PathBuf};
use tracing::{error, info, warn}; use tracing::{error, info, warn};
#[cfg(feature = "egui-ui")] #[cfg(feature = "egui-ui")]
use veloren_voxygen::ui::egui::EguiState; use veloren_voxygen::ui::egui::EguiState;
#[allow(clippy::manual_unwrap_or)] #[allow(clippy::manual_unwrap_or)]
fn main() { fn main() {
let userdata_dir = common_base::userdata_dir_workspace!();
// Determine where Voxygen's logs should go
// Choose a path to store the logs by the following order:
// - The VOXYGEN_LOGS environment variable
// - The <userdata>/voxygen/logs
let logs_dir = std::env::var_os("VOXYGEN_LOGS")
.map(PathBuf::from)
.unwrap_or_else(|| userdata_dir.join("voxygen").join("logs"));
// Init logging and hold the guards.
const LOG_FILENAME: &str = "voxygen.log";
let _guards = common_frontend::init_stdout(Some((&logs_dir, LOG_FILENAME)));
info!("Using userdata dir at: {}", userdata_dir.display());
// Determine Voxygen's config directory either by env var or placed in veloren's
// userdata folder
let config_dir = std::env::var_os("VOXYGEN_CONFIG")
.map(PathBuf::from)
.and_then(|path| {
if path.exists() {
Some(path)
} else {
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
None
}
})
.unwrap_or_else(|| userdata_dir.join("voxygen"));
info!("Using config dir at: {}", config_dir.display());
// Load the settings // Load the settings
// Note: This won't log anything due to it being called before // Note: This won't log anything due to it being called before
// `logging::init`. The issue is we need to read a setting to decide // `logging::init`. The issue is we need to read a setting to decide
// whether we create a log file or not. // whether we create a log file or not.
let mut settings = Settings::load(); let mut settings = Settings::load(&config_dir);
// Save settings to add new fields or create the file if it is not already there // Save settings to add new fields or create the file if it is not already there
if let Err(err) = settings.save_to_file() { if let Err(err) = settings.save_to_file(&config_dir) {
panic!("Failed to save settings: {:?}", err); panic!("Failed to save settings: {:?}", err);
} }
// Init logging and hold the guards.
const LOG_FILENAME: &str = "voxygen.log";
let _guards = common_frontend::init_stdout(Some((&settings.log.logs_path, LOG_FILENAME)));
if let Some(path) = veloren_voxygen::settings::voxygen_data_dir().parent() {
info!("Using userdata dir at: {}", path.display());
} else {
error!("Can't log userdata dir, voxygen data dir has no parent!");
}
// Set up panic handler to relay swish panic messages to the user // Set up panic handler to relay swish panic messages to the user
let default_hook = panic::take_hook(); let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |panic_info| { panic::set_hook(Box::new(move |panic_info| {
@ -92,9 +113,7 @@ fn main() {
Panic Payload: {:?}\n\ Panic Payload: {:?}\n\
PanicInfo: {}\n\ PanicInfo: {}\n\
Game version: {} [{}]", Game version: {} [{}]",
Settings::load() logs_dir
.log
.logs_path
.join("voxygen-<date>.log") .join("voxygen-<date>.log")
.display(), .display(),
reason, reason,
@ -171,7 +190,7 @@ fn main() {
audio.set_sfx_volume(settings.audio.sfx_volume); audio.set_sfx_volume(settings.audio.sfx_volume);
// Load the profile. // Load the profile.
let profile = Profile::load(); let profile = Profile::load(&config_dir);
let mut i18n = let mut i18n =
LocalizationHandle::load(&settings.language.selected_language).unwrap_or_else(|error| { LocalizationHandle::load(&settings.language.selected_language).unwrap_or_else(|error| {
@ -198,6 +217,8 @@ fn main() {
let egui_state = EguiState::new(&window); let egui_state = EguiState::new(&window);
let global_state = GlobalState { let global_state = GlobalState {
userdata_dir,
config_dir,
audio, audio,
profile, profile,
window, window,

View File

@ -139,7 +139,9 @@ impl PlayState for CharSelectionState {
global_state global_state
.profile .profile
.set_selected_character(server_name, selected); .set_selected_character(server_name, selected);
global_state.profile.save_to_file_warn(); global_state
.profile
.save_to_file_warn(&global_state.config_dir);
}, },
} }
} }
@ -185,7 +187,9 @@ impl PlayState for CharSelectionState {
match event { match event {
client::Event::SetViewDistance(vd) => { client::Event::SetViewDistance(vd) => {
global_state.settings.graphics.view_distance = vd; global_state.settings.graphics.view_distance = vd;
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
}, },
client::Event::Disconnect => { client::Event::Disconnect => {
global_state.info_message = Some( global_state.info_message = Some(

View File

@ -175,7 +175,9 @@ impl PlayState for MainMenuState {
match event { match event {
client::Event::SetViewDistance(vd) => { client::Event::SetViewDistance(vd) => {
global_state.settings.graphics.view_distance = vd; global_state.settings.graphics.view_distance = vd;
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
}, },
client::Event::Disconnect => { client::Event::Disconnect => {
global_state.info_message = Some( global_state.info_message = Some(
@ -238,7 +240,9 @@ impl PlayState for MainMenuState {
if !net_settings.servers.contains(&server_address) { if !net_settings.servers.contains(&server_address) {
net_settings.servers.push(server_address.clone()); net_settings.servers.push(server_address.clone());
} }
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
let connection_args = if use_quic { let connection_args = if use_quic {
ConnectionArgs::Quic { ConnectionArgs::Quic {
@ -302,7 +306,9 @@ impl PlayState for MainMenuState {
.networking .networking
.trusted_auth_servers .trusted_auth_servers
.insert(auth_server.clone()); .insert(auth_server.clone());
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
} }
self.init self.init
.client() .client()

View File

@ -1,100 +0,0 @@
use common::comp;
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use std::{fs, io::Write, path::PathBuf};
use tracing::warn;
const VALID_VERSION: u32 = 0; // Change this if you broke charsaves
#[derive(Clone, Debug, Serialize, Deserialize)]
#[repr(C)]
pub struct CharacterData {
pub name: String,
pub body: comp::Body,
pub tool: Option<String>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
//#[serde(default)]
#[repr(C)]
pub struct Meta {
pub characters: Vec<CharacterData>,
pub selected_character: usize,
pub version: u32,
}
impl Meta {
pub fn delete_character(&mut self, index: usize) {
self.characters.remove(index);
if index < self.selected_character {
self.selected_character -= 1;
}
}
pub fn add_character(&mut self, data: CharacterData) -> usize {
self.characters.push(data);
// return new character's index
self.characters.len() - 1
}
pub fn load() -> Self {
let path = Self::get_meta_path();
if let Ok(file) = fs::File::open(&path) {
match ron::de::from_reader::<_, Meta>(file) {
Ok(s) => {
if s.version == VALID_VERSION {
return s;
}
},
Err(e) => {
warn!(?e, ?file, "Failed to parse meta file! Fallback to default");
// Rename the corrupted settings file
let mut new_path = path.to_owned();
new_path.pop();
new_path.push("meta.invalid.ron");
if let Err(e) = std::fs::rename(path.clone(), new_path.clone()) {
warn!(?e, ?path, ?new_path, "Failed to rename meta file");
}
},
}
}
// This is reached if either:
// - The file can't be opened (presumably it doesn't exist)
// - Or there was an error parsing the file
let default = Self::default();
default.save_to_file_warn();
default
}
pub fn save_to_file_warn(&self) {
if let Err(err) = self.save_to_file() {
warn!(?e, "Failed to save settings");
}
}
pub fn save_to_file(&self) -> std::io::Result<()> {
let path = Self::get_meta_path();
if let Some(dir) = path.parent() {
fs::create_dir_all(dir)?;
}
let mut meta_file = fs::File::create(path)?;
let s: &str = &ron::ser::to_string_pretty(self, ron::ser::PrettyConfig::default()).unwrap();
meta_file.write_all(s.as_bytes()).unwrap();
Ok(())
}
pub fn get_meta_path() -> PathBuf {
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
let meta = PathBuf::from(path).join("meta.ron");
if meta.exists() || meta.parent().map(|x| x.exists()).unwrap_or(false) {
return meta;
}
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
}
let proj_dirs = ProjectDirs::from("net", "veloren", "voxygen")
.expect("System's $HOME directory path not found!");
proj_dirs.config_dir().join("meta").with_extension("ron")
}
}

View File

@ -1,8 +1,12 @@
use crate::{hud, settings}; use crate::hud;
use common::{character::CharacterId, comp::slot::InvSlotId}; use common::{character::CharacterId, comp::slot::InvSlotId};
use hashbrown::HashMap; use hashbrown::HashMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fs, io::Write, path::PathBuf}; use std::{
fs,
io::Write,
path::{Path, PathBuf},
};
use tracing::warn; use tracing::warn;
/// Represents a character in the profile. /// Represents a character in the profile.
@ -76,8 +80,8 @@ impl Default for Profile {
impl Profile { impl Profile {
/// Load the profile.ron file from the standard path or create it. /// Load the profile.ron file from the standard path or create it.
pub fn load() -> Self { pub fn load(config_dir: &Path) -> Self {
let path = Profile::get_path(); let path = Profile::get_path(config_dir);
if let Ok(file) = fs::File::open(&path) { if let Ok(file) = fs::File::open(&path) {
match ron::de::from_reader(file) { match ron::de::from_reader(file) {
@ -100,13 +104,13 @@ impl Profile {
// - The file can't be opened (presumably it doesn't exist) // - The file can't be opened (presumably it doesn't exist)
// - Or there was an error parsing the file // - Or there was an error parsing the file
let default_profile = Self::default(); let default_profile = Self::default();
default_profile.save_to_file_warn(); default_profile.save_to_file_warn(config_dir);
default_profile default_profile
} }
/// Save the current profile to disk, warn on failure. /// Save the current profile to disk, warn on failure.
pub fn save_to_file_warn(&self) { pub fn save_to_file_warn(&self, config_dir: &Path) {
if let Err(e) = self.save_to_file() { if let Err(e) = self.save_to_file(config_dir) {
warn!(?e, "Failed to save profile"); warn!(?e, "Failed to save profile");
} }
} }
@ -194,8 +198,8 @@ impl Profile {
} }
/// Save the current profile to disk. /// Save the current profile to disk.
fn save_to_file(&self) -> std::io::Result<()> { fn save_to_file(&self, config_dir: &Path) -> std::io::Result<()> {
let path = Profile::get_path(); let path = Profile::get_path(config_dir);
if let Some(dir) = path.parent() { if let Some(dir) = path.parent() {
fs::create_dir_all(dir)?; fs::create_dir_all(dir)?;
} }
@ -206,19 +210,7 @@ impl Profile {
Ok(()) Ok(())
} }
fn get_path() -> PathBuf { fn get_path(config_dir: &Path) -> PathBuf { config_dir.join("profile.ron") }
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
let profile = PathBuf::from(path.clone()).join("profile.ron");
if profile.exists() || profile.parent().map(|x| x.exists()).unwrap_or(false) {
return profile;
}
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
}
let mut path = settings::voxygen_data_dir();
path.push("profile.ron");
path
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -83,8 +83,12 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
}, },
winit::event::Event::LoopDestroyed => { winit::event::Event::LoopDestroyed => {
// Save any unsaved changes to settings and profile // Save any unsaved changes to settings and profile
global_state.settings.save_to_file_warn(); global_state
global_state.profile.save_to_file_warn(); .settings
.save_to_file_warn(&global_state.config_dir);
global_state
.profile
.save_to_file_warn(&global_state.config_dir);
}, },
_ => {}, _ => {},
} }
@ -100,7 +104,7 @@ fn handle_main_events_cleared(
// Screenshot / Fullscreen toggle // Screenshot / Fullscreen toggle
global_state global_state
.window .window
.resolve_deduplicated_events(&mut global_state.settings); .resolve_deduplicated_events(&mut global_state.settings, &global_state.config_dir);
// Run tick here // Run tick here
// What's going on here? // What's going on here?

View File

@ -259,7 +259,9 @@ impl SessionState {
}, },
client::Event::SetViewDistance(vd) => { client::Event::SetViewDistance(vd) => {
global_state.settings.graphics.view_distance = vd; global_state.settings.graphics.view_distance = vd;
global_state.settings.save_to_file_warn(); global_state
.settings
.save_to_file_warn(&global_state.config_dir);
}, },
client::Event::Outcome(outcome) => outcomes.push(outcome), client::Event::Outcome(outcome) => outcomes.push(outcome),
client::Event::CharacterCreated(_) => {}, client::Event::CharacterCreated(_) => {},
@ -1305,7 +1307,9 @@ impl PlayState for SessionState {
state.slots, state.slots,
); );
global_state.profile.save_to_file_warn(); global_state
.profile
.save_to_file_warn(&global_state.config_dir);
info!("Event! -> ChangedHotbarState") info!("Event! -> ChangedHotbarState")
}, },

View File

@ -202,7 +202,6 @@ impl SettingsChange {
global_state.audio.set_sfx_volume(audio.sfx_volume); global_state.audio.set_sfx_volume(audio.sfx_volume);
}, },
} }
settings.save_to_file_warn();
}, },
SettingsChange::Chat(chat_change) => { SettingsChange::Chat(chat_change) => {
let chat_tabs = &mut settings.chat.chat_tabs; let chat_tabs = &mut settings.chat.chat_tabs;
@ -242,7 +241,6 @@ impl SettingsChange {
settings.chat = ChatSettings::default(); settings.chat = ChatSettings::default();
}, },
} }
settings.save_to_file_warn();
}, },
SettingsChange::Control(control_change) => match control_change { SettingsChange::Control(control_change) => match control_change {
Control::ChangeBinding(game_input) => { Control::ChangeBinding(game_input) => {
@ -250,7 +248,6 @@ impl SettingsChange {
}, },
Control::ResetKeyBindings => { Control::ResetKeyBindings => {
settings.controls = ControlSettings::default(); settings.controls = ControlSettings::default();
settings.save_to_file_warn();
}, },
}, },
SettingsChange::Gamepad(gamepad_change) => match gamepad_change {}, SettingsChange::Gamepad(gamepad_change) => match gamepad_change {},
@ -323,7 +320,6 @@ impl SettingsChange {
window.mouse_y_inversion = settings.gameplay.mouse_y_inversion; window.mouse_y_inversion = settings.gameplay.mouse_y_inversion;
}, },
} }
settings.save_to_file_warn();
}, },
SettingsChange::Graphics(graphics_change) => { SettingsChange::Graphics(graphics_change) => {
match graphics_change { match graphics_change {
@ -423,7 +419,6 @@ impl SettingsChange {
global_state.window.set_size(graphics.window_size.into()); global_state.window.set_size(graphics.window_size.into());
}, },
} }
settings.save_to_file_warn();
}, },
SettingsChange::Interface(interface_change) => { SettingsChange::Interface(interface_change) => {
match interface_change { match interface_change {
@ -534,7 +529,6 @@ impl SettingsChange {
.set_scaling_mode(settings.interface.ui_scale); .set_scaling_mode(settings.interface.ui_scale);
}, },
} }
settings.save_to_file_warn();
}, },
SettingsChange::Language(language_change) => match language_change { SettingsChange::Language(language_change) => match language_change {
Language::ChangeLanguage(new_language) => { Language::ChangeLanguage(new_language) => {
@ -556,5 +550,6 @@ impl SettingsChange {
}, },
SettingsChange::Networking(networking_change) => match networking_change {}, SettingsChange::Networking(networking_change) => match networking_change {},
} }
settings.save_to_file_warn(&global_state.config_dir);
} }
} }

View File

@ -1,6 +1,9 @@
use directories_next::UserDirs; use directories_next::UserDirs;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::{fs, path::PathBuf}; use std::{
fs,
path::{Path, PathBuf},
};
use tracing::warn; use tracing::warn;
pub mod audio; pub mod audio;
@ -23,40 +26,6 @@ pub use interface::InterfaceSettings;
pub use language::LanguageSettings; pub use language::LanguageSettings;
pub use networking::NetworkingSettings; pub use networking::NetworkingSettings;
/// `Log` stores whether we should create a log file
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(default)]
pub struct Log {
// Whether to create a log file or not.
// Default is to create one.
pub log_to_file: bool,
// The path on which the logs will be stored
pub logs_path: PathBuf,
}
impl Default for Log {
fn default() -> Self {
// Chooses a path to store the logs by the following order:
// - The VOXYGEN_LOGS environment variable
// - The ProjectsDirs data local directory
// This function is only called if there isn't already an entry in the settings
// file. However, the VOXYGEN_LOGS environment variable always overrides
// the log file path if set.
let logs_path = std::env::var_os("VOXYGEN_LOGS")
.map(PathBuf::from)
.unwrap_or_else(|| {
let mut path = voxygen_data_dir();
path.push("logs");
path
});
Self {
log_to_file: true,
logs_path,
}
}
}
/// `Settings` contains everything that can be configured in the settings.ron /// `Settings` contains everything that can be configured in the settings.ron
/// file. /// file.
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -67,7 +36,6 @@ pub struct Settings {
pub interface: InterfaceSettings, pub interface: InterfaceSettings,
pub gameplay: GameplaySettings, pub gameplay: GameplaySettings,
pub networking: NetworkingSettings, pub networking: NetworkingSettings,
pub log: Log,
pub graphics: GraphicsSettings, pub graphics: GraphicsSettings,
pub audio: AudioSettings, pub audio: AudioSettings,
pub show_disclaimer: bool, pub show_disclaimer: bool,
@ -104,7 +72,6 @@ impl Default for Settings {
interface: InterfaceSettings::default(), interface: InterfaceSettings::default(),
gameplay: GameplaySettings::default(), gameplay: GameplaySettings::default(),
networking: NetworkingSettings::default(), networking: NetworkingSettings::default(),
log: Log::default(),
graphics: GraphicsSettings::default(), graphics: GraphicsSettings::default(),
audio: AudioSettings::default(), audio: AudioSettings::default(),
show_disclaimer: true, show_disclaimer: true,
@ -118,25 +85,12 @@ impl Default for Settings {
} }
impl Settings { impl Settings {
pub fn load() -> Self { pub fn load(config_dir: &Path) -> Self {
let path = Self::get_settings_path(); let path = Self::get_path(config_dir);
if let Ok(file) = fs::File::open(&path) { if let Ok(file) = fs::File::open(&path) {
match ron::de::from_reader::<_, Self>(file) { match ron::de::from_reader::<_, Self>(file) {
Ok(mut s) => { Ok(s) => return s,
// Override the logs path if it is explicitly set using the VOXYGEN_LOGS
// environment variable. This is needed to support package managers that enforce
// strict application confinement (e.g. snap). In fact, the veloren snap package
// relies on this environment variable to be respected in
// order to communicate a path where the snap package is
// allowed to write to.
if let Some(logs_path_override) =
std::env::var_os("VOXYGEN_LOGS").map(PathBuf::from)
{
s.log.logs_path = logs_path_override;
}
return s;
},
Err(e) => { Err(e) => {
warn!(?e, "Failed to parse setting file! Fallback to default."); warn!(?e, "Failed to parse setting file! Fallback to default.");
// Rename the corrupted settings file // Rename the corrupted settings file
@ -153,18 +107,18 @@ impl Settings {
// - The file can't be opened (presumably it doesn't exist) // - The file can't be opened (presumably it doesn't exist)
// - Or there was an error parsing the file // - Or there was an error parsing the file
let default_settings = Self::default(); let default_settings = Self::default();
default_settings.save_to_file_warn(); default_settings.save_to_file_warn(config_dir);
default_settings default_settings
} }
pub fn save_to_file_warn(&self) { pub fn save_to_file_warn(&self, config_dir: &Path) {
if let Err(e) = self.save_to_file() { if let Err(e) = self.save_to_file(config_dir) {
warn!(?e, "Failed to save settings"); warn!(?e, "Failed to save settings");
} }
} }
pub fn save_to_file(&self) -> std::io::Result<()> { pub fn save_to_file(&self, config_dir: &Path) -> std::io::Result<()> {
let path = Self::get_settings_path(); let path = Self::get_path(config_dir);
if let Some(dir) = path.parent() { if let Some(dir) = path.parent() {
fs::create_dir_all(dir)?; fs::create_dir_all(dir)?;
} }
@ -173,25 +127,5 @@ impl Settings {
fs::write(path, ron.as_bytes()) fs::write(path, ron.as_bytes())
} }
pub fn get_settings_path() -> PathBuf { fn get_path(config_dir: &Path) -> PathBuf { config_dir.join("settings.ron") }
if let Some(path) = std::env::var_os("VOXYGEN_CONFIG") {
let settings = PathBuf::from(&path).join("settings.ron");
if settings.exists() || settings.parent().map(|x| x.exists()).unwrap_or(false) {
return settings;
}
warn!(?path, "VOXYGEN_CONFIG points to invalid path.");
}
let mut path = voxygen_data_dir();
path.push("settings.ron");
path
}
}
pub fn voxygen_data_dir() -> PathBuf {
// Note: since voxygen is technically a lib we made need to lift this up to
// run.rs
let mut path = common_base::userdata_dir_workspace!();
path.push("voxygen");
path
} }

View File

@ -703,7 +703,11 @@ impl Window {
pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer } pub fn renderer_mut(&mut self) -> &mut Renderer { &mut self.renderer }
pub fn resolve_deduplicated_events(&mut self, settings: &mut Settings) { pub fn resolve_deduplicated_events(
&mut self,
settings: &mut Settings,
config_dir: &std::path::Path,
) {
// Handle screenshots and toggling fullscreen // Handle screenshots and toggling fullscreen
if self.take_screenshot { if self.take_screenshot {
self.take_screenshot = false; self.take_screenshot = false;
@ -711,7 +715,7 @@ impl Window {
} }
if self.toggle_fullscreen { if self.toggle_fullscreen {
self.toggle_fullscreen = false; self.toggle_fullscreen = false;
self.toggle_fullscreen(settings); self.toggle_fullscreen(settings, config_dir);
} }
} }
@ -1170,7 +1174,7 @@ impl Window {
} }
} }
pub fn toggle_fullscreen(&mut self, settings: &mut Settings) { pub fn toggle_fullscreen(&mut self, settings: &mut Settings, config_dir: &std::path::Path) {
let fullscreen = FullScreenSettings { let fullscreen = FullScreenSettings {
enabled: !self.is_fullscreen(), enabled: !self.is_fullscreen(),
..settings.graphics.fullscreen ..settings.graphics.fullscreen
@ -1178,7 +1182,7 @@ impl Window {
self.set_fullscreen_mode(fullscreen); self.set_fullscreen_mode(fullscreen);
settings.graphics.fullscreen = fullscreen; settings.graphics.fullscreen = fullscreen;
settings.save_to_file_warn(); settings.save_to_file_warn(config_dir);
} }
pub fn is_fullscreen(&self) -> bool { self.fullscreen.enabled } pub fn is_fullscreen(&self) -> bool { self.fullscreen.enabled }