feat(config): load cosmic-randr output Lists
This commit is contained in:
parent
416b66b776
commit
bb8e066d6d
18 changed files with 270 additions and 34 deletions
159
cosmic-comp-config/src/output/comp.rs
Normal file
159
cosmic-comp-config/src/output/comp.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fs::OpenOptions, path::Path};
|
||||
use tracing::{error, warn};
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct EdidProduct {
|
||||
pub manufacturer: [char; 3],
|
||||
pub product: u16,
|
||||
pub serial: Option<u32>,
|
||||
pub manufacture_week: i32,
|
||||
pub manufacture_year: i32,
|
||||
pub model_year: Option<i32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "libdisplay-info")]
|
||||
impl From<libdisplay_info::edid::VendorProduct> for EdidProduct {
|
||||
fn from(vp: libdisplay_info::edid::VendorProduct) -> Self {
|
||||
Self {
|
||||
manufacturer: vp.manufacturer,
|
||||
product: vp.product,
|
||||
serial: vp.serial,
|
||||
manufacture_week: vp.manufacture_week,
|
||||
manufacture_year: vp.manufacture_year,
|
||||
model_year: vp.model_year,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum OutputState {
|
||||
#[serde(rename = "true")]
|
||||
Enabled,
|
||||
#[serde(rename = "false")]
|
||||
Disabled,
|
||||
Mirroring(String),
|
||||
}
|
||||
|
||||
fn default_state() -> OutputState {
|
||||
OutputState::Enabled
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, Copy, PartialEq)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum AdaptiveSync {
|
||||
#[serde(rename = "true")]
|
||||
Enabled,
|
||||
#[serde(rename = "false")]
|
||||
Disabled,
|
||||
Force,
|
||||
}
|
||||
|
||||
fn default_sync() -> AdaptiveSync {
|
||||
AdaptiveSync::Enabled
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct OutputsConfig {
|
||||
pub config: HashMap<Vec<OutputInfo>, Vec<OutputConfig>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
|
||||
pub struct OutputConfig {
|
||||
pub mode: ((i32, i32), Option<u32>),
|
||||
#[serde(default = "default_sync")]
|
||||
pub vrr: AdaptiveSync,
|
||||
pub scale: f64,
|
||||
pub transform: TransformDef,
|
||||
pub position: (u32, u32),
|
||||
#[serde(default = "default_state")]
|
||||
pub enabled: OutputState,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub max_bpc: Option<u32>,
|
||||
#[serde(default)]
|
||||
pub xwayland_primary: bool,
|
||||
}
|
||||
|
||||
impl Default for OutputConfig {
|
||||
fn default() -> OutputConfig {
|
||||
OutputConfig {
|
||||
mode: ((0, 0), None),
|
||||
vrr: AdaptiveSync::Enabled,
|
||||
scale: 1.0,
|
||||
transform: TransformDef::Normal,
|
||||
position: (0, 0),
|
||||
enabled: OutputState::Enabled,
|
||||
max_bpc: None,
|
||||
xwayland_primary: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub struct OutputInfo {
|
||||
pub connector: String,
|
||||
pub make: String,
|
||||
pub model: String,
|
||||
}
|
||||
|
||||
pub fn load_outputs(path: Option<impl AsRef<Path>>) -> OutputsConfig {
|
||||
if let Some(path) = path.as_ref() {
|
||||
let path: &Path = path.as_ref();
|
||||
if path.exists() {
|
||||
match ron::de::from_reader::<_, OutputsConfig>(
|
||||
OpenOptions::new().read(true).open(path).unwrap(),
|
||||
) {
|
||||
Ok(mut config) => {
|
||||
for (info, config) in config.config.iter_mut() {
|
||||
let config_clone = config.clone();
|
||||
for conf in config.iter_mut() {
|
||||
if let OutputState::Mirroring(conn) = &conf.enabled {
|
||||
if let Some((j, _)) = info
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, info)| &info.connector == conn)
|
||||
{
|
||||
if config_clone[j].enabled != OutputState::Enabled {
|
||||
warn!("Invalid Mirroring tag, overriding with `Enabled` instead");
|
||||
conf.enabled = OutputState::Enabled;
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Invalid Mirroring tag, overriding with `Enabled` instead"
|
||||
);
|
||||
conf.enabled = OutputState::Enabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
Err(err) => {
|
||||
warn!(?err, "Failed to read output_config, resetting..");
|
||||
if let Err(err) = std::fs::remove_file(path) {
|
||||
error!(?err, "Failed to remove output_config.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
OutputsConfig {
|
||||
config: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum TransformDef {
|
||||
Normal,
|
||||
_90,
|
||||
_180,
|
||||
_270,
|
||||
Flipped,
|
||||
Flipped90,
|
||||
Flipped180,
|
||||
Flipped270,
|
||||
}
|
||||
6
cosmic-comp-config/src/output/mod.rs
Normal file
6
cosmic-comp-config/src/output/mod.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/// Internal output configurations used by cosmic-comp
|
||||
pub mod comp;
|
||||
|
||||
#[cfg(feature = "randr")]
|
||||
/// cosmic-randr style output configurations
|
||||
pub mod randr;
|
||||
90
cosmic-comp-config/src/output/randr.rs
Normal file
90
cosmic-comp-config/src/output/randr.rs
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
use std::path::Path;
|
||||
|
||||
use cosmic_randr_shell::{AdaptiveSyncState, List};
|
||||
|
||||
use crate::output::comp::OutputState;
|
||||
|
||||
pub struct CompList {
|
||||
infos: Vec<super::comp::OutputInfo>,
|
||||
outputs: Vec<super::comp::OutputConfig>,
|
||||
}
|
||||
|
||||
impl From<CompList> for cosmic_randr_shell::List {
|
||||
fn from(CompList { infos, outputs }: CompList) -> cosmic_randr_shell::List {
|
||||
let mut list = cosmic_randr_shell::List::default();
|
||||
for (info, output) in infos.into_iter().zip(outputs.into_iter()) {
|
||||
let current = list.modes.insert(cosmic_randr_shell::Mode {
|
||||
size: (output.mode.0 .0 as u32, output.mode.0 .1 as u32),
|
||||
refresh_rate: output.mode.1.unwrap_or_default(),
|
||||
// XXX not in config as far as i can tell
|
||||
preferred: false,
|
||||
});
|
||||
let modes = vec![current];
|
||||
|
||||
// for mode in output. {}
|
||||
list.outputs.insert(cosmic_randr_shell::Output {
|
||||
name: info.connector,
|
||||
enabled: !matches!(output.enabled, OutputState::Disabled),
|
||||
mirroring: match output.enabled {
|
||||
OutputState::Mirroring(m) => Some(m),
|
||||
_ => None,
|
||||
},
|
||||
make: Some(info.make),
|
||||
model: info.model,
|
||||
position: (output.position.0 as i32, output.position.1 as i32),
|
||||
scale: output.scale,
|
||||
transform: Some(match output.transform {
|
||||
crate::output::comp::TransformDef::Normal => {
|
||||
cosmic_randr_shell::Transform::Normal
|
||||
}
|
||||
crate::output::comp::TransformDef::_90 => {
|
||||
cosmic_randr_shell::Transform::Rotate90
|
||||
}
|
||||
crate::output::comp::TransformDef::_180 => {
|
||||
cosmic_randr_shell::Transform::Rotate180
|
||||
}
|
||||
crate::output::comp::TransformDef::_270 => {
|
||||
cosmic_randr_shell::Transform::Rotate270
|
||||
}
|
||||
crate::output::comp::TransformDef::Flipped => {
|
||||
cosmic_randr_shell::Transform::Flipped
|
||||
}
|
||||
crate::output::comp::TransformDef::Flipped90 => {
|
||||
cosmic_randr_shell::Transform::Flipped90
|
||||
}
|
||||
crate::output::comp::TransformDef::Flipped180 => {
|
||||
cosmic_randr_shell::Transform::Flipped180
|
||||
}
|
||||
crate::output::comp::TransformDef::Flipped270 => {
|
||||
cosmic_randr_shell::Transform::Flipped270
|
||||
}
|
||||
}),
|
||||
modes,
|
||||
current: Some(current),
|
||||
adaptive_sync: Some(match output.vrr {
|
||||
crate::output::comp::AdaptiveSync::Enabled => AdaptiveSyncState::Auto,
|
||||
crate::output::comp::AdaptiveSync::Disabled => AdaptiveSyncState::Disabled,
|
||||
crate::output::comp::AdaptiveSync::Force => AdaptiveSyncState::Always,
|
||||
}),
|
||||
xwayland_primary: Some(output.xwayland_primary),
|
||||
// XXX no physical output size in the config
|
||||
physical: (0, 0),
|
||||
adaptive_sync_availability: None,
|
||||
});
|
||||
}
|
||||
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_outputs(path: Option<impl AsRef<Path>>) -> Vec<List> {
|
||||
let output_config = crate::output::comp::load_outputs(path);
|
||||
output_config
|
||||
.config
|
||||
.into_iter()
|
||||
.map(|(infos, outputs)| {
|
||||
let comp_config = CompList { infos, outputs };
|
||||
List::from(comp_config)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue