From 0e2141ac6c93db5e36dff7e870c26f01bed11ce3 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Wed, 20 Aug 2025 18:06:41 -0400 Subject: [PATCH] refactor: use randr kdl command cleanup chore: update deps fix: typo --- Cargo.lock | 76 ++++++----- Cargo.toml | 9 +- daemon/Cargo.toml | 3 + daemon/src/lib.rs | 20 ++- src/greeter.rs | 330 +++++++++------------------------------------- 5 files changed, 125 insertions(+), 313 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dd42a48..217c663 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1100,9 +1100,10 @@ dependencies = [ [[package]] name = "cosmic-comp-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-comp?branch=refactor-config#f59af1685b38b8cc339e542ffab3b3cf82ac00b6" +source = "git+https://github.com/pop-os/cosmic-comp?branch=refactor-config#2c1106b41f62d57f90fb5976684f890f2751272d" dependencies = [ "cosmic-config", + "cosmic-randr-shell", "input", "ron 0.9.0", "serde", @@ -1112,7 +1113,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "atomicwrites", "calloop 0.14.3", @@ -1135,7 +1136,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "quote", "syn 2.0.106", @@ -1171,7 +1172,7 @@ dependencies = [ "dirs 5.0.1", "ini_core", "memmap2 0.9.7", - "thiserror 2.0.15", + "thiserror 2.0.16", "tracing", "xdg 2.5.2", ] @@ -1206,6 +1207,7 @@ dependencies = [ "i18n-embed-fl", "icu", "itoa", + "kdl", "libcosmic", "log", "logind-zbus", @@ -1243,8 +1245,10 @@ dependencies = [ "cosmic-bg-config", "cosmic-comp-config", "cosmic-config", + "cosmic-randr-shell", "cosmic-theme", "env_logger", + "kdl", "libc", "log", "nix 0.29.0", @@ -1273,11 +1277,11 @@ dependencies = [ [[package]] name = "cosmic-randr-shell" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-randr#f2cf6dfe9af22c005018b1aa952347dcc1d80b1c" +source = "git+https://github.com/pop-os/cosmic-randr?branch=kdl-command#4b2dcdc840774f919e94abdf4088d658c7bd1ebf" dependencies = [ "kdl", "slotmap", - "thiserror 2.0.15", + "thiserror 2.0.16", "tokio", ] @@ -1290,7 +1294,7 @@ dependencies = [ "ron 0.9.0", "serde", "serde_with", - "thiserror 2.0.15", + "thiserror 2.0.16", "tracing", "xkbcommon", ] @@ -1330,7 +1334,7 @@ dependencies = [ "num-derive", "num-traits", "smithay-client-toolkit", - "thiserror 2.0.15", + "thiserror 2.0.16", "tokio", "tokio-stream", "tracing", @@ -1362,7 +1366,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "almost", "cosmic-config", @@ -1373,7 +1377,7 @@ dependencies = [ "ron 0.9.0", "serde", "serde_json", - "thiserror 2.0.15", + "thiserror 2.0.16", ] [[package]] @@ -2125,7 +2129,7 @@ dependencies = [ "gettext-rs", "log", "memchr", - "thiserror 2.0.15", + "thiserror 2.0.16", "unicase", "xdg 2.5.2", ] @@ -2663,7 +2667,7 @@ dependencies = [ [[package]] name = "iced" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "dnd", "iced_accessibility", @@ -2681,7 +2685,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "accesskit", "accesskit_winit", @@ -2690,7 +2694,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "bitflags 2.9.2", "bytes", @@ -2715,7 +2719,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "futures", "iced_core", @@ -2741,7 +2745,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "bitflags 2.9.2", "bytemuck", @@ -2763,7 +2767,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -2775,7 +2779,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "bytes", "cosmic-client-toolkit", @@ -2791,7 +2795,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "bytemuck", "cosmic-text", @@ -2807,7 +2811,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "as-raw-xcb-connection", "bitflags 2.9.2", @@ -2838,7 +2842,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "cosmic-client-toolkit", "dnd", @@ -2858,7 +2862,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.14.0-dev" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "cosmic-client-toolkit", "dnd", @@ -3733,7 +3737,7 @@ checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#6e7a6343981df7d86f7ab01fe102d0b69d8e3bed" +source = "git+https://github.com/pop-os/libcosmic#29f38f83a38b550ae0de2b130fde9f2c36341fab" dependencies = [ "apply", "ashpd", @@ -3770,7 +3774,7 @@ dependencies = [ "shlex", "slotmap", "taffy", - "thiserror 2.0.15", + "thiserror 2.0.16", "tokio", "tracing", "unicode-segmentation", @@ -5314,7 +5318,7 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.16", "libredox", - "thiserror 2.0.15", + "thiserror 2.0.16", ] [[package]] @@ -6122,15 +6126,15 @@ checksum = "83176759e9416cf81ee66cb6508dbfe9c96f20b8b56265a39917551c23c70964" [[package]] name = "tempfile" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" dependencies = [ "fastrand 2.3.0", "getrandom 0.3.3", "once_cell", "rustix 1.0.8", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -6153,11 +6157,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d76d3f064b981389ecb4b6b7f45a0bf9fdac1d5b9204c7bd6714fecc302850" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.15", + "thiserror-impl 2.0.16", ] [[package]] @@ -6173,9 +6177,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d29feb33e986b6ea906bd9c3559a856983f92371b3eaa5e83782a351623de0" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -7080,11 +7084,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 3138ca9..80e6a6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,9 +77,11 @@ i18n-embed-fl = "0.7" rust-embed = "8" futures-util = "0.3.30" timedate-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" } -cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr", default-features = false } tachyonix = "0.3.1" itoa = "1.0.15" +cosmic-randr-shell = { workspace = true } +kdl.workspace = true + [dependencies.greetd_ipc] version = "0.10.3" @@ -120,6 +122,9 @@ ron = "0.10.1" serde = "1" tokio = "1.39.1" zbus = "5" +kdl = "6" +cosmic-randr-shell = { git = "https://github.com/pop-os/cosmic-randr", default-features = false, branch = "kdl-command" } +# cosmic-randr-shell = { path = "../cosmic-randr/shell", default-features = false } [workspace.dependencies.cosmic-applets-config] git = "https://github.com/pop-os/cosmic-applets" @@ -134,7 +139,7 @@ git = "https://github.com/pop-os/cosmic-comp" branch = "refactor-config" # path = "../cosmic-comp/cosmic-comp-config" default-features = false -features = ["output"] +features = ["output", "randr"] [workspace.dependencies.cosmic-greeter-config] path = "cosmic-greeter-config" diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index a5b98d9..1e1a7da 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -19,6 +19,9 @@ pwd.workspace = true ron.workspace = true serde.workspace = true zbus.workspace = true +cosmic-randr-shell.workspace = true +kdl.workspace = true + #TODO: reduce features tokio = { workspace = true, features = ["full"] } xdg = "3.0.0" diff --git a/daemon/src/lib.rs b/daemon/src/lib.rs index 7c14bdb..74546c5 100644 --- a/daemon/src/lib.rs +++ b/daemon/src/lib.rs @@ -1,5 +1,6 @@ -use cosmic_comp_config::output::{self, OutputsConfig}; +use cosmic_comp_config::output::randr; use cosmic_config::CosmicConfigEntry; +use kdl::KdlDocument; use std::{ collections::BTreeMap, fs, @@ -24,7 +25,7 @@ pub struct UserData { pub xkb_config_opt: Option, pub time_applet_config: TimeAppletConfig, pub accessibility_zoom: ZoomConfig, - pub outputs: Option, + pub kdl_output_lists: Vec, } impl UserData { @@ -178,10 +179,17 @@ impl UserData { }; let xdg = xdg::BaseDirectories::new(); - self.outputs = xdg.get_state_home().map(|mut s| { - s.push("cosmic-comp/outputs.ron"); - output::load_outputs(Some(&s)) - }); + self.kdl_output_lists = xdg + .get_state_home() + .map(|mut s| { + s.push("cosmic-comp/outputs.ron"); + let lists = randr::load_outputs(Some(&s)); + lists + .into_iter() + .map(|l| KdlDocument::from(l).to_string()) + .collect() + }) + .unwrap_or_default(); match cosmic_config::Config::new("com.system76.CosmicAppletTime", TimeAppletConfig::VERSION) { diff --git a/src/greeter.rs b/src/greeter.rs index 2bd73e2..9b2e541 100644 --- a/src/greeter.rs +++ b/src/greeter.rs @@ -17,7 +17,7 @@ use cosmic::{ iced::{ self, Background, Border, Length, Subscription, alignment, event::wayland::OutputEvent, - futures::{self, SinkExt}, + futures::SinkExt, platform_specific::{ runtime::wayland::layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings}, shell::wayland::commands::layer_surface::{ @@ -32,16 +32,15 @@ use cosmic::{ cosmic_theme::{self, CosmicPalette}, surface, }; -use cosmic_comp_config::output::{OutputConfig, OutputInfo, OutputState}; use cosmic_greeter_config::Config as CosmicGreeterConfig; use cosmic_greeter_daemon::UserData; -use cosmic_randr_shell::{ - AdaptiveSyncAvailability, AdaptiveSyncState, List, Output, OutputKey, Transform, -}; +use cosmic_randr_shell::{AdaptiveSyncState, KdlParseWithError, List, OutputKey, Transform}; use cosmic_settings_subscriptions::cosmic_a11y_manager::{ AccessibilityEvent, AccessibilityRequest, }; use greetd_ipc::Request; +use kdl::KdlDocument; +use std::process::Stdio; use std::sync::LazyLock; use std::{ collections::{HashMap, hash_map}, @@ -437,257 +436,34 @@ struct Accessibility { impl App { /// Applies a display configuration via `cosmic-randr`. - fn exec_randr(&self, output: Output, user_config: OutputConfig) -> Task { - let Some(current_mode) = output.current else { - log::warn!("Current output mode missing..."); - return Task::none(); - }; - let Some(current_mode) = self - .randr_list - .as_ref() - .and_then(|l| l.modes.get(current_mode)) - else { - log::warn!("Mode key does not exist..."); - return Task::none(); - }; - let Some(list) = self.randr_list.as_ref() else { - return Task::none(); - }; + fn exec_randr(&self, user_config: cosmic_randr_shell::List) -> Task { + let mut task = tokio::process::Command::new("cosmic-randr"); + task.arg("kdl"); - let mut tasks = Vec::new(); - let name = &*output.name; + cosmic::task::future::<(), ()>(async move { + task.stdin(Stdio::piped()); + let Ok(mut p) = task.spawn() else { + return; + }; - // Mirror - let cur_state = if output.enabled { - output - .mirroring - .map(|n| OutputState::Mirroring(n)) - .unwrap_or(OutputState::Enabled) - } else { - OutputState::Disabled - }; - // Enable/Disable or Mirror - if user_config.enabled != cur_state { - match user_config.enabled { - OutputState::Enabled => { - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("enable").arg(name); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); + let kdl_doc = kdl::KdlDocument::from(user_config).to_string(); + use tokio::io::AsyncWriteExt; + + if let Some(mut stdin) = p.stdin.take() { + if let Err(err) = stdin.write_all(kdl_doc.as_bytes()).await { + log::error!("Failed to write KDL to stdin: {err:?}"); } - OutputState::Disabled => { - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("disable").arg(name); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - OutputState::Mirroring(ref mirror_name) => { - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mirror").arg(&output.name).arg(mirror_name); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); + if let Err(err) = stdin.flush().await { + log::error!("Failed to flush stdin: {err:?}"); } } - } - - // Position - if (user_config.position.0 as i32, user_config.position.1 as i32) != output.position { - let (x, y) = user_config.position; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg("--pos-x") - .arg(itoa::Buffer::new().format(x)) - .arg("--pos-y") - .arg(itoa::Buffer::new().format(y)) - .arg(name) - .arg(itoa::Buffer::new().format(current_mode.size.0)) - .arg(itoa::Buffer::new().format(current_mode.size.1)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - // RefreshRate - if user_config.mode.1 != Some(current_mode.refresh_rate) { - let rate = current_mode.refresh_rate; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg("--refresh") - .arg(format!("{}.{:03}", rate / 1000, rate % 1000)) - .arg(name) - .arg(itoa::Buffer::new().format(current_mode.size.0)) - .arg(itoa::Buffer::new().format(current_mode.size.1)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - let configured_vrr = match user_config.vrr { - cosmic_comp_config::output::AdaptiveSync::Enabled => { - cosmic_randr_shell::AdaptiveSyncState::Auto + log::debug!("executing {task:?}"); + let status = p.wait().await; + if let Err(err) = status { + log::error!("Randr error: {err:?}"); } - cosmic_comp_config::output::AdaptiveSync::Disabled => { - cosmic_randr_shell::AdaptiveSyncState::Disabled - } - cosmic_comp_config::output::AdaptiveSync::Force => { - cosmic_randr_shell::AdaptiveSyncState::Always - } - }; - // VariableRefreshRate - if Some(configured_vrr) != output.adaptive_sync { - let mode = configured_vrr; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg("--adaptive-sync") - .arg(format!("{}", mode)) - .arg(name) - .arg(itoa::Buffer::new().format(current_mode.size.0)) - .arg(itoa::Buffer::new().format(current_mode.size.1)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - // Resolution - if (user_config.mode.0.0 as u32, user_config.mode.0.1 as u32) != current_mode.size { - let (width, height) = user_config.mode.0; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg(name) - .arg(itoa::Buffer::new().format(width)) - .arg(itoa::Buffer::new().format(height)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - // Scale - if user_config.scale != user_config.scale { - let scale = user_config.scale; - let rate = current_mode.refresh_rate; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg("--scale") - .arg(format!("{:02}", scale / 100.)) - .arg("--refresh") - .arg(format!("{}.{:03}", rate / 1000, rate % 1000)) - .arg(name) - .arg(itoa::Buffer::new().format(current_mode.size.0)) - .arg(itoa::Buffer::new().format(current_mode.size.1)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - // Transform - - let configured_transform = match user_config.transform { - cosmic_comp_config::output::TransformDef::Normal => { - cosmic_randr_shell::Transform::Normal - } - cosmic_comp_config::output::TransformDef::_90 => { - cosmic_randr_shell::Transform::Rotate90 - } - cosmic_comp_config::output::TransformDef::_180 => { - cosmic_randr_shell::Transform::Rotate180 - } - cosmic_comp_config::output::TransformDef::_270 => { - cosmic_randr_shell::Transform::Rotate270 - } - cosmic_comp_config::output::TransformDef::Flipped => { - cosmic_randr_shell::Transform::Flipped - } - cosmic_comp_config::output::TransformDef::Flipped90 => { - cosmic_randr_shell::Transform::Flipped90 - } - cosmic_comp_config::output::TransformDef::Flipped180 => { - cosmic_randr_shell::Transform::Flipped180 - } - cosmic_comp_config::output::TransformDef::Flipped270 => { - cosmic_randr_shell::Transform::Flipped270 - } - }; - if Some(configured_transform) != output.transform { - let transform = configured_transform; - let mut task = tokio::process::Command::new("cosmic-randr"); - task.arg("mode") - .arg("--transform") - .arg(&*format!("{transform}")) - .arg(name) - .arg(itoa::Buffer::new().format(current_mode.size.0)) - .arg(itoa::Buffer::new().format(current_mode.size.1)); - tasks.push( - cosmic::task::future::<(), ()>(async move { - log::debug!("executing {task:?}"); - let status = task.status().await; - if let Err(err) = status { - log::error!("Randr error: {err:?}"); - } - }) - .discard(), - ); - } - - Task::batch(tasks) + }) + .discard() } fn menu(&self, id: SurfaceId) -> Element { @@ -1870,43 +1646,59 @@ impl cosmic::Application for App { let mut tasks = Vec::new(); self.randr_list = Some(outputs.clone()); - let mut output_pairs: Vec<(Output, OutputInfo, OutputConfig)> = Vec::new(); + let mut list: Option = None; let Some(cur_user_output_state) = self .selected_username .data_idx .and_then(|i| self.flags.user_datas.get(i)) - .and_then(|user_data| user_data.outputs.as_ref()) + .map(|user_data| &user_data.kdl_output_lists) else { return Task::none(); }; - 'outer: for (i, (configured_info, output_configs)) in - cur_user_output_state.config.iter().enumerate() + 'outer: for configured_list in cur_user_output_state + .iter() + .filter_map(|s| match KdlDocument::parse(s) { + Ok(doc) => Some(doc), + Err(err) => { + log::warn!("Invalid output KDL {err:?}"); + None + } + }) + .map(|kdl| match List::try_from(kdl) { + Ok(list) => list, + Err(KdlParseWithError { list, errors }) => { + for err in errors { + log::warn!("KDL output error: {err:?}"); + } + list + } + }) { - if configured_info.len() != outputs.outputs.len() { + if configured_list.outputs.len() != outputs.outputs.len() { continue; } - let mut matching_outputs = Vec::new(); for o in outputs.outputs.values() { - if let Some(pos) = configured_info.iter().position(|configured| { - configured.connector == o.name - && configured.make == o.make.clone().unwrap_or_default() - && configured.model == o.model + if configured_list.outputs.values().all(|configured| { + configured.name != o.name + || configured.make != o.make + || configured.model != o.model }) { - matching_outputs.push(( - o.clone(), - configured_info[pos].clone(), - output_configs[pos].clone(), - )); - } else { continue 'outer; } } - output_pairs = matching_outputs; + if list + .as_ref() + .is_none_or(|old| old.outputs.len() < configured_list.outputs.len()) + { + list = Some(configured_list); + } } - for (randr_o, _info, user_config) in output_pairs { - tasks.push(self.exec_randr(randr_o, user_config)) + if let Some(list) = list { + tasks.push(self.exec_randr(list)) + } else { + log::warn!("Failed to apply user display config"); } return Task::batch(tasks);