refactor(output config): move to config crate

this allows the greeter to easily sync to the user config
This commit is contained in:
Ashley Wulber 2025-08-19 16:51:37 -04:00 committed by Ashley Wulber
parent 4a385d5535
commit 416b66b776
17 changed files with 283 additions and 194 deletions

3
Cargo.lock generated
View file

@ -828,6 +828,7 @@ dependencies = [
"cosmic-text", "cosmic-text",
"egui", "egui",
"egui_plot", "egui_plot",
"futures",
"i18n-embed", "i18n-embed",
"i18n-embed-fl", "i18n-embed-fl",
"iced_tiny_skia", "iced_tiny_skia",
@ -880,7 +881,9 @@ dependencies = [
"cosmic-config", "cosmic-config",
"input", "input",
"libdisplay-info", "libdisplay-info",
"ron 0.9.0",
"serde", "serde",
"tracing",
] ]
[[package]] [[package]]

View file

@ -88,6 +88,7 @@ reis = { version = "0.5", features = ["calloop"] }
clap_lex = "0.7" clap_lex = "0.7"
parking_lot = "0.12.4" parking_lot = "0.12.4"
logind-zbus = { version = "5.3.2", optional = true } logind-zbus = { version = "5.3.2", optional = true }
futures = "0.3.31"
[dependencies.id_tree] [dependencies.id_tree]
branch = "feature/copy_clone" branch = "feature/copy_clone"

View file

@ -8,3 +8,12 @@ cosmic-config = { git = "https://github.com/pop-os/libcosmic/" }
input = "0.9.0" input = "0.9.0"
libdisplay-info = { version = "0.2.0", optional = true } libdisplay-info = { version = "0.2.0", optional = true }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
ron = { version = "0.9.0-alpha.0", optional = true }
tracing = { version = "0.1.37", features = [
"max_level_debug",
"release_max_level_info",
], optional = true }
[features]
default = ["output"]
output = ["ron", "tracing"]

View file

@ -7,6 +7,7 @@ use std::collections::HashMap;
use crate::input::TouchpadOverride; use crate::input::TouchpadOverride;
pub mod input; pub mod input;
#[cfg(feature = "output")]
pub mod output; pub mod output;
pub mod workspace; pub mod workspace;

View file

@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use serde::{Deserialize, Serialize}; 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)] #[derive(Debug, Deserialize, Serialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EdidProduct { pub struct EdidProduct {
@ -25,3 +27,133 @@ impl From<libdisplay_info::edid::VendorProduct> for EdidProduct {
} }
} }
} }
#[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,
}

View file

@ -5,13 +5,14 @@ use crate::{
kms::render::gles::GbmGlowBackend, kms::render::gles::GbmGlowBackend,
render::{init_shaders, output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR}, render::{init_shaders, output_elements, CursorMode, GlMultiRenderer, CLEAR_COLOR},
}, },
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState, ScreenFilter}, config::{CompTransformDef, EdidProduct, ScreenFilter},
shell::Shell, shell::Shell,
utils::{env::dev_list_var, prelude::*}, utils::{env::dev_list_var, prelude::*},
wayland::handlers::screencopy::PendingImageCopyData, wayland::handlers::screencopy::PendingImageCopyData,
}; };
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use cosmic_comp_config::output::{AdaptiveSync, OutputConfig, OutputState};
use libc::dev_t; use libc::dev_t;
use smithay::{ use smithay::{
backend::{ backend::{
@ -1008,7 +1009,7 @@ fn populate_modes(
position, position,
max_bpc, max_bpc,
scale, scale,
transform, transform: CompTransformDef::from(transform).0,
// Try opportunistic VRR by default, // Try opportunistic VRR by default,
// if not supported this will be turned off on `resume`, // if not supported this will be turned off on `resume`,
// when we have the `Surface` to actually check for support. // when we have the `Surface` to actually check for support.

View file

@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::{
config::{AdaptiveSync, OutputState, ScreenFilter}, config::{CompOutputConfig, ScreenFilter},
shell::Shell, shell::Shell,
state::BackendData, state::BackendData,
utils::{env::dev_var, prelude::*}, utils::{env::dev_var, prelude::*},
@ -9,6 +9,7 @@ use crate::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use calloop::LoopSignal; use calloop::LoopSignal;
use cosmic_comp_config::output::{AdaptiveSync, OutputState};
use indexmap::IndexMap; use indexmap::IndexMap;
use render::gles::GbmGlowBackend; use render::gles::GbmGlowBackend;
use smithay::{ use smithay::{
@ -798,7 +799,7 @@ impl<'a> KmsGuard<'a> {
// reconfigure existing // reconfigure existing
for (crtc, surface) in device.inner.surfaces.iter_mut() { for (crtc, surface) in device.inner.surfaces.iter_mut() {
let output_config = surface.output.config(); let output_config = CompOutputConfig(surface.output.config());
let drm = &mut device.drm; let drm = &mut device.drm;
let conn = surface.connector; let conn = surface.connector;
@ -814,7 +815,7 @@ impl<'a> KmsGuard<'a> {
// and then select the closest refresh rate (e.g. to match 59.98 as 60) // and then select the closest refresh rate (e.g. to match 59.98 as 60)
.min_by_key(|mode| { .min_by_key(|mode| {
let refresh_rate = drm_helpers::calculate_refresh_rate(**mode); let refresh_rate = drm_helpers::calculate_refresh_rate(**mode);
(output_config.mode.1.unwrap() as i32 - refresh_rate as i32).abs() (output_config.0.mode.1.unwrap() as i32 - refresh_rate as i32).abs()
}) })
.ok_or(anyhow::anyhow!("Unable to find matching mode"))?; .ok_or(anyhow::anyhow!("Unable to find matching mode"))?;
@ -876,7 +877,7 @@ impl<'a> KmsGuard<'a> {
compositor compositor
}; };
if let Some(bpc) = output_config.max_bpc { if let Some(bpc) = output_config.0.max_bpc {
if let Err(err) = drm_helpers::set_max_bpc(drm.device(), conn, bpc) { if let Err(err) = drm_helpers::set_max_bpc(drm.device(), conn, bpc) {
warn!( warn!(
?bpc, ?bpc,
@ -887,7 +888,7 @@ impl<'a> KmsGuard<'a> {
} }
} }
let vrr = output_config.vrr; let vrr = output_config.0.vrr;
std::mem::drop(output_config); std::mem::drop(output_config);
let compositor_ref = drm.compositors().get(crtc).unwrap().lock().unwrap(); let compositor_ref = drm.compositors().get(crtc).unwrap().lock().unwrap();
@ -928,7 +929,7 @@ impl<'a> KmsGuard<'a> {
surface.output.set_adaptive_sync(AdaptiveSync::Disabled); surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
} }
} else { } else {
let vrr = output_config.vrr; let vrr = output_config.0.vrr;
std::mem::drop(output_config); std::mem::drop(output_config);
if vrr != surface.output.adaptive_sync() { if vrr != surface.output.adaptive_sync() {
if match surface.output.adaptive_sync_support() { if match surface.output.adaptive_sync_support() {
@ -1030,7 +1031,7 @@ impl<'a> KmsGuard<'a> {
Some( Some(
all_outputs all_outputs
.iter() .iter()
.find(|output| &output.name() == conn) .find(|output| output.name() == *conn)
.cloned() .cloned()
.ok_or(anyhow::anyhow!("Unable to find mirroring output"))?, .ok_or(anyhow::anyhow!("Unable to find mirroring output"))?,
) )

View file

@ -6,7 +6,7 @@ use crate::{
init_shaders, output_elements, CursorMode, GlMultiError, GlMultiRenderer, init_shaders, output_elements, CursorMode, GlMultiError, GlMultiRenderer,
PostprocessOutputConfig, PostprocessShader, PostprocessState, CLEAR_COLOR, PostprocessOutputConfig, PostprocessShader, PostprocessState, CLEAR_COLOR,
}, },
config::{AdaptiveSync, ScreenFilter}, config::ScreenFilter,
shell::Shell, shell::Shell,
state::SurfaceDmabufFeedback, state::SurfaceDmabufFeedback,
utils::prelude::*, utils::prelude::*,
@ -23,6 +23,7 @@ use crate::{
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use calloop::channel::Channel; use calloop::channel::Channel;
use cosmic_comp_config::output::AdaptiveSync;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{ allocator::{

View file

@ -2,12 +2,13 @@
use crate::{ use crate::{
backend::render, backend::render,
config::{OutputConfig, ScreenFilter}, config::ScreenFilter,
shell::{Devices, SeatExt}, shell::{Devices, SeatExt},
state::{BackendData, Common}, state::{BackendData, Common},
utils::prelude::*, utils::prelude::*,
}; };
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use cosmic_comp_config::output::{OutputConfig, TransformDef};
use smithay::{ use smithay::{
backend::{ backend::{
drm::NodeType, drm::NodeType,
@ -167,7 +168,7 @@ pub fn init_backend(
output.user_data().insert_if_missing(|| { output.user_data().insert_if_missing(|| {
RefCell::new(OutputConfig { RefCell::new(OutputConfig {
mode: ((size.w, size.h), None), mode: ((size.w, size.h), None),
transform: Transform::Flipped180.into(), transform: TransformDef::Flipped180,
..Default::default() ..Default::default()
}) })
}); });

View file

@ -2,12 +2,13 @@
use crate::{ use crate::{
backend::render, backend::render,
config::{OutputConfig, ScreenFilter}, config::ScreenFilter,
shell::{Devices, SeatExt}, shell::{Devices, SeatExt},
state::{BackendData, Common}, state::{BackendData, Common},
utils::prelude::*, utils::prelude::*,
}; };
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use cosmic_comp_config::output::OutputConfig;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{ allocator::{

View file

@ -28,7 +28,7 @@ pub use smithay::{
utils::{Logical, Physical, Point, Size, Transform, SERIAL_COUNTER}, utils::{Logical, Physical, Point, Size, Transform, SERIAL_COUNTER},
}; };
use std::{ use std::{
cell::RefCell, cell::{Ref, RefCell},
collections::{BTreeMap, HashMap}, collections::{BTreeMap, HashMap},
fs::OpenOptions, fs::OpenOptions,
io::Write, io::Write,
@ -39,17 +39,19 @@ use tracing::{error, warn};
mod input_config; mod input_config;
pub mod key_bindings; pub mod key_bindings;
pub use key_bindings::{Action, PrivateAction};
mod types; mod types;
pub use self::types::*;
use cosmic::config::CosmicTk; use cosmic::config::CosmicTk;
pub use cosmic_comp_config::output::EdidProduct; pub use cosmic_comp_config::output::EdidProduct;
use cosmic_comp_config::{ use cosmic_comp_config::{
input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride}, input::{DeviceState as InputDeviceState, InputConfig, TouchpadOverride},
output::{load_outputs, OutputConfig, OutputInfo, OutputState, OutputsConfig, TransformDef},
workspace::WorkspaceConfig, workspace::WorkspaceConfig,
CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling, CosmicCompConfig, KeyboardConfig, TileBehavior, XkbConfig, XwaylandDescaling,
XwaylandEavesdropping, ZoomConfig, XwaylandEavesdropping, ZoomConfig,
}; };
pub use key_bindings::{Action, PrivateAction};
use types::WlXkbConfig;
#[derive(Debug)] #[derive(Debug)]
pub struct Config { pub struct Config {
@ -74,105 +76,24 @@ pub struct DynamicConfig {
accessibility_filter: (Option<PathBuf>, ScreenFilter), accessibility_filter: (Option<PathBuf>, ScreenFilter),
} }
#[derive(Debug, Deserialize, Serialize)]
pub struct OutputsConfig {
pub config: HashMap<Vec<OutputInfo>, Vec<OutputConfig>>,
}
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutputInfo {
pub connector: String,
pub make: String,
pub model: String,
}
impl From<Output> for OutputInfo {
fn from(o: Output) -> OutputInfo {
let physical = o.physical_properties();
OutputInfo {
connector: o.name(),
make: physical.make,
model: physical.model,
}
}
}
#[derive(Default, Debug, Deserialize, Serialize)] #[derive(Default, Debug, Deserialize, Serialize)]
pub struct NumlockStateConfig { pub struct NumlockStateConfig {
pub last_state: bool, pub last_state: bool,
} }
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)] pub struct CompOutputConfig<'a>(pub Ref<'a, OutputConfig>);
#[serde(rename_all = "lowercase")]
pub enum OutputState {
#[serde(rename = "true")]
Enabled,
#[serde(rename = "false")]
Disabled,
Mirroring(String),
}
fn default_state() -> OutputState { impl<'a> CompOutputConfig<'a> {
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, Deserialize, Serialize, Clone, PartialEq)]
pub struct OutputConfig {
pub mode: ((i32, i32), Option<u32>),
#[serde(default = "default_sync")]
pub vrr: AdaptiveSync,
pub scale: f64,
#[serde(with = "TransformDef")]
pub transform: Transform,
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: Transform::Normal,
position: (0, 0),
enabled: OutputState::Enabled,
max_bpc: None,
xwayland_primary: false,
}
}
}
impl OutputConfig {
pub fn mode_size(&self) -> Size<i32, Physical> { pub fn mode_size(&self) -> Size<i32, Physical> {
self.mode.0.into() self.0.mode.0.into()
} }
pub fn mode_refresh(&self) -> u32 { pub fn mode_refresh(&self) -> u32 {
self.mode.1.unwrap_or(60_000) self.0.mode.1.unwrap_or(60_000)
} }
pub fn transformed_size(&self) -> Size<i32, Physical> { pub fn transformed_size(&self) -> Size<i32, Physical> {
self.transform.transform_size(self.mode_size()) self.transform().transform_size(self.mode_size())
} }
pub fn output_mode(&self) -> Mode { pub fn output_mode(&self) -> Mode {
@ -181,6 +102,57 @@ impl OutputConfig {
refresh: self.mode_refresh() as i32, refresh: self.mode_refresh() as i32,
} }
} }
pub fn transform(&self) -> Transform {
Transform::from(CompTransformDef(self.0.transform))
}
}
pub struct CompTransformDef(pub TransformDef);
impl From<Transform> for CompTransformDef {
fn from(transform: Transform) -> Self {
let def = match transform {
Transform::Normal => TransformDef::Normal,
Transform::_90 => TransformDef::_90,
Transform::_180 => TransformDef::_180,
Transform::_270 => TransformDef::_270,
Transform::Flipped => TransformDef::Flipped,
Transform::Flipped90 => TransformDef::Flipped90,
Transform::Flipped180 => TransformDef::Flipped180,
Transform::Flipped270 => TransformDef::Flipped270,
};
CompTransformDef(def)
}
}
impl From<CompTransformDef> for Transform {
fn from(comp_transform: CompTransformDef) -> Self {
match comp_transform.0 {
TransformDef::Normal => Transform::Normal,
TransformDef::_90 => Transform::_90,
TransformDef::_180 => Transform::_180,
TransformDef::_270 => Transform::_270,
TransformDef::Flipped => Transform::Flipped,
TransformDef::Flipped90 => Transform::Flipped90,
TransformDef::Flipped180 => Transform::Flipped180,
TransformDef::Flipped270 => Transform::Flipped270,
}
}
}
#[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, Default, Deserialize, Serialize, Clone, PartialEq)] #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq)]
@ -355,7 +327,7 @@ impl Config {
fn load_dynamic(xdg: &xdg::BaseDirectories) -> DynamicConfig { fn load_dynamic(xdg: &xdg::BaseDirectories) -> DynamicConfig {
let output_path = xdg.place_state_file("cosmic-comp/outputs.ron").ok(); let output_path = xdg.place_state_file("cosmic-comp/outputs.ron").ok();
let outputs = Self::load_outputs(&output_path); let outputs = load_outputs(output_path.as_ref());
let numlock_path = xdg.place_state_file("cosmic-comp/numlock.ron").ok(); let numlock_path = xdg.place_state_file("cosmic-comp/numlock.ron").ok();
let numlock = Self::load_numlock(&numlock_path); let numlock = Self::load_numlock(&numlock_path);
@ -371,54 +343,6 @@ impl Config {
} }
} }
fn load_outputs(path: &Option<PathBuf>) -> OutputsConfig {
if let Some(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(),
}
}
fn load_numlock(path: &Option<PathBuf>) -> NumlockStateConfig { fn load_numlock(path: &Option<PathBuf>) -> NumlockStateConfig {
path.as_deref() path.as_deref()
.filter(|path| path.exists()) .filter(|path| path.exists())
@ -479,7 +403,8 @@ impl Config {
let mut infos = outputs let mut infos = outputs
.iter() .iter()
.cloned() .cloned()
.map(Into::<crate::config::OutputInfo>::into) .map(Into::<crate::config::CompOutputInfo>::into)
.map(|i| i.0)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
infos.sort(); infos.sort();
@ -657,7 +582,7 @@ impl Config {
.map(|o| { .map(|o| {
let o = o.borrow(); let o = o.borrow();
( (
Into::<crate::config::OutputInfo>::into(o.clone()), Into::<CompOutputInfo>::into(o.clone()).0,
o.user_data() o.user_data()
.get::<RefCell<OutputConfig>>() .get::<RefCell<OutputConfig>>()
.unwrap() .unwrap()
@ -801,6 +726,16 @@ impl DynamicConfig {
} }
} }
pub fn xkb_config_to_wl(config: &XkbConfig) -> WlXkbConfig<'_> {
WlXkbConfig {
rules: &config.rules,
model: &config.model,
layout: &config.layout,
variant: &config.variant,
options: config.options.clone(),
}
}
fn get_config<T: Default + serde::de::DeserializeOwned>( fn get_config<T: Default + serde::de::DeserializeOwned>(
config: &cosmic_config::Config, config: &cosmic_config::Config,
key: &str, key: &str,
@ -1002,12 +937,16 @@ fn config_changed(config: cosmic_config::Config, keys: Vec<String>, state: &mut
} }
} }
pub fn xkb_config_to_wl(config: &XkbConfig) -> WlXkbConfig<'_> { #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
WlXkbConfig { pub struct CompOutputInfo(OutputInfo);
rules: &config.rules,
model: &config.model, impl From<Output> for CompOutputInfo {
layout: &config.layout, fn from(o: Output) -> CompOutputInfo {
variant: &config.variant, let physical = o.physical_properties();
options: config.options.clone(), CompOutputInfo(OutputInfo {
connector: o.name(),
make: physical.make,
model: physical.model,
})
} }
} }

View file

@ -1,18 +1,4 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
#![allow(non_snake_case)] #![allow(non_snake_case)]
use serde::{Deserialize, Serialize}; pub use smithay::input::keyboard::XkbConfig as WlXkbConfig;
pub use smithay::{input::keyboard::XkbConfig as WlXkbConfig, utils::Transform};
#[derive(Serialize, Deserialize)]
#[serde(remote = "Transform")]
pub enum TransformDef {
Normal,
_90,
_180,
_270,
Flipped,
Flipped90,
Flipped180,
Flipped270,
}

View file

@ -7,7 +7,7 @@ use crate::{
winit::WinitState, winit::WinitState,
x11::X11State, x11::X11State,
}, },
config::{Config, OutputConfig, OutputState, ScreenFilter}, config::{CompOutputConfig, Config, ScreenFilter},
input::{gestures::GestureState, PointerFocusState}, input::{gestures::GestureState, PointerFocusState},
shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell}, shell::{grabs::SeatMoveGrabState, CosmicSurface, SeatExt, Shell},
utils::prelude::OutputExt, utils::prelude::OutputExt,
@ -31,6 +31,7 @@ use crate::{
}; };
use anyhow::Context; use anyhow::Context;
use calloop::RegistrationToken; use calloop::RegistrationToken;
use cosmic_comp_config::output::{OutputConfig, OutputState};
use i18n_embed::{ use i18n_embed::{
fluent::{fluent_language_loader, FluentLanguageLoader}, fluent::{fluent_language_loader, FluentLanguageLoader},
DesktopLanguageRequester, DesktopLanguageRequester,
@ -455,28 +456,30 @@ impl<'a> LockedBackend<'a> {
// update outputs, so that `OutputModeSource`s are correct // update outputs, so that `OutputModeSource`s are correct
for output in &all_outputs { for output in &all_outputs {
// apply to Output // apply to Output
let final_config = output let final_config = CompOutputConfig(
.user_data() output
.get::<RefCell<OutputConfig>>() .user_data()
.unwrap() .get::<RefCell<OutputConfig>>()
.borrow(); .unwrap()
.borrow(),
);
let mode = Some(final_config.output_mode()).filter(|m| match output.current_mode() { let mode = Some(final_config.output_mode()).filter(|m| match output.current_mode() {
None => true, None => true,
Some(c_m) => m.size != c_m.size || m.refresh != c_m.refresh, Some(c_m) => m.size != c_m.size || m.refresh != c_m.refresh,
}); });
let transform = let transform =
Some(final_config.transform.into()).filter(|x| *x != output.current_transform()); Some(final_config.transform()).filter(|x| *x != output.current_transform());
let scale = Some(final_config.scale) let scale = Some(final_config.0.scale)
.filter(|x| *x != output.current_scale().fractional_scale()); .filter(|x| *x != output.current_scale().fractional_scale());
let location = Some(Point::from(( let location = Some(Point::from((
final_config.position.0 as i32, final_config.0.position.0 as i32,
final_config.position.1 as i32, final_config.0.position.1 as i32,
))) )))
.filter(|x| *x != output.current_location()); .filter(|x| *x != output.current_location());
output.change_current_state(mode, transform, scale.map(Scale::Fractional), location); output.change_current_state(mode, transform, scale.map(Scale::Fractional), location);
output.set_adaptive_sync(final_config.vrr); output.set_adaptive_sync(final_config.0.vrr);
} }
match self { match self {

View file

@ -1,3 +1,4 @@
use cosmic_comp_config::output::{AdaptiveSync, OutputConfig, OutputState};
use smithay::{ use smithay::{
backend::drm::VrrSupport as Support, backend::drm::VrrSupport as Support,
output::{Output, WeakOutput}, output::{Output, WeakOutput},
@ -8,10 +9,7 @@ pub use super::geometry::*;
pub use crate::shell::{SeatExt, Shell, Workspace}; pub use crate::shell::{SeatExt, Shell, Workspace};
pub use crate::state::{Common, State}; pub use crate::state::{Common, State};
pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups; pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups;
use crate::{ use crate::{config::EdidProduct, shell::zoom::OutputZoomState};
config::{AdaptiveSync, EdidProduct, OutputConfig, OutputState},
shell::zoom::OutputZoomState,
};
use std::{ use std::{
cell::{Ref, RefCell, RefMut}, cell::{Ref, RefCell, RefMut},

View file

@ -1,10 +1,10 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use cosmic_comp_config::output::{OutputConfig, OutputState, TransformDef};
use smithay::{output::Output, utils::Point}; use smithay::{output::Output, utils::Point};
use tracing::{error, warn}; use tracing::{error, warn};
use crate::{ use crate::{
config::{OutputConfig, OutputState},
state::State, state::State,
utils::prelude::OutputExt, utils::prelude::OutputExt,
wayland::protocols::output_configuration::{ wayland::protocols::output_configuration::{
@ -123,7 +123,16 @@ impl State {
current_config.scale = *scale; current_config.scale = *scale;
} }
if let Some(transform) = transform { if let Some(transform) = transform {
current_config.transform = *transform; current_config.transform = match transform {
smithay::utils::Transform::Normal => TransformDef::Normal,
smithay::utils::Transform::_90 => TransformDef::_90,
smithay::utils::Transform::_180 => TransformDef::_180,
smithay::utils::Transform::_270 => TransformDef::_270,
smithay::utils::Transform::Flipped => TransformDef::Flipped,
smithay::utils::Transform::Flipped90 => TransformDef::Flipped90,
smithay::utils::Transform::Flipped180 => TransformDef::Flipped180,
smithay::utils::Transform::Flipped270 => TransformDef::Flipped270,
}
} }
if let Some(position) = position { if let Some(position) = position {
current_config.position = (position.x as u32, position.y as u32); current_config.position = (position.x as u32, position.y as u32);

View file

@ -14,6 +14,8 @@ use smithay::{
}, },
}; };
use cosmic_comp_config::output::OutputState as EnabledState;
use cosmic_protocols::output_management::v1::server::{ use cosmic_protocols::output_management::v1::server::{
zcosmic_output_configuration_head_v1::{self, ZcosmicOutputConfigurationHeadV1}, zcosmic_output_configuration_head_v1::{self, ZcosmicOutputConfigurationHeadV1},
zcosmic_output_configuration_v1::{self, ZcosmicOutputConfigurationV1}, zcosmic_output_configuration_v1::{self, ZcosmicOutputConfigurationV1},
@ -21,7 +23,7 @@ use cosmic_protocols::output_management::v1::server::{
zcosmic_output_manager_v1::{self, ZcosmicOutputManagerV1}, zcosmic_output_manager_v1::{self, ZcosmicOutputManagerV1},
}; };
use crate::{config::OutputState as EnabledState, wayland::protocols::output_configuration::*}; use crate::wayland::protocols::output_configuration::*;
impl<D> GlobalDispatch<ZcosmicOutputManagerV1, OutputMngrGlobalData, D> impl<D> GlobalDispatch<ZcosmicOutputManagerV1, OutputMngrGlobalData, D>
for OutputConfigurationState<D> for OutputConfigurationState<D>

View file

@ -4,6 +4,7 @@ use calloop::{
timer::{TimeoutAction, Timer}, timer::{TimeoutAction, Timer},
LoopHandle, LoopHandle,
}; };
use cosmic_comp_config::output::AdaptiveSync;
use cosmic_protocols::output_management::v1::server::{ use cosmic_protocols::output_management::v1::server::{
zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1, zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1,
zcosmic_output_configuration_v1::ZcosmicOutputConfigurationV1, zcosmic_output_configuration_v1::ZcosmicOutputConfigurationV1,
@ -580,4 +581,4 @@ macro_rules! delegate_output_configuration {
} }
pub(crate) use delegate_output_configuration; pub(crate) use delegate_output_configuration;
use crate::{config::AdaptiveSync, utils::prelude::OutputExt}; use crate::utils::prelude::OutputExt;