pub mod error;
pub mod types;
pub mod traits;
pub mod backends;
pub use error::{DisplayError, DisplayResult};
pub use traits::{OutputEditable, UniversalTopology};
pub use types::*;
#[cfg(target_os = "windows")]
pub use backends::windows::{
force_activate_by_monitor_name, force_all,
activate_display, ActivationResult,
WinDisplayManager,
};
#[cfg(target_os = "windows")]
pub use crate::backends::NativeTopology;
#[cfg(target_os = "linux")]
pub use crate::backends::NativeTopology;
pub async fn activate_with_topology_restore(
target_id: u32,
plan: &ActivationPlan,
) -> DisplayResult<()> {
use std::collections::HashMap;
use traits::UniversalTopology;
#[derive(Debug, Clone)]
struct SavedOutput {
_name: String,
enabled: bool,
x: i32,
y: i32,
width: u32,
height: u32,
}
let saved: HashMap<String, SavedOutput> = {
let topo = NativeTopology::acquire()?;
let outputs = topo.get_outputs();
let mut map = HashMap::new();
for o in &outputs {
map.insert(
o.identity.id.0.clone(),
SavedOutput {
_name: o.identity.monitor_name.trim().to_string(),
enabled: o.enabled,
x: o.geometry.origin.x,
y: o.geometry.origin.y,
width: o.geometry.size.width,
height: o.geometry.size.height,
},
);
}
map
};
force_all().map_err(|e| DisplayError::BackendError(e.to_string()))?;
#[cfg(target_os = "windows")]
{
tokio::task::spawn_blocking(|| {
std::thread::sleep(std::time::Duration::from_millis(800));
}).await.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
{
let mut topo = NativeTopology::acquire()?;
let outputs = topo.get_outputs();
let target_id_str = target_id.to_string();
for o in &outputs {
let id_str = &o.identity.id.0;
if let Some(s) = saved.get(id_str) {
if s.enabled {
let did = DisplayId(id_str.clone());
if let Ok(mut editor) = topo.edit_output(&did) {
let _ = editor.set_enabled(true);
let _ = editor.set_position(types::Point2D { x: s.x, y: s.y });
let _ = editor.set_resolution(types::Extent2D {
width: s.width,
height: s.height,
});
}
} else {
let did = DisplayId(id_str.clone());
if let Ok(mut editor) = topo.edit_output(&did) {
let _ = editor.set_enabled(false);
}
}
} else if id_str == &target_id_str {
} else {
let did = DisplayId(id_str.clone());
if let Ok(mut editor) = topo.edit_output(&did) {
let _ = editor.set_enabled(false);
}
}
}
topo.set_persistence(true);
let _ = topo.validate().await;
topo.commit().await
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
#[cfg(target_os = "windows")]
{
tokio::task::spawn_blocking(|| {
std::thread::sleep(std::time::Duration::from_millis(800));
}).await.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
let was_active = saved.get(&target_id.to_string())
.map(|s| s.enabled)
.unwrap_or(false);
if was_active {
return Ok(());
}
let pos = match plan.position {
Some(p) => p,
None => {
let topo = NativeTopology::acquire()?;
let right_x = topo.get_outputs()
.iter()
.filter(|o| o.enabled)
.map(|o| o.geometry.origin.x + o.geometry.size.width as i32)
.max()
.unwrap_or(0);
types::Point2D { x: right_x, y: 0 }
}
};
{
let mut topo = NativeTopology::acquire()?;
let did = DisplayId(target_id.to_string());
let mut editor = topo.edit_output(&did)
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
editor.set_enabled(true)
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
editor.set_position(pos)
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
if let Some(res) = plan.resolution {
editor.set_resolution(res)
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
if let Some(rot) = plan.rotation {
editor.set_rotation(rot)
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
drop(editor);
topo.set_persistence(true);
let _ = topo.validate().await;
topo.commit().await
.map_err(|e| DisplayError::BackendError(e.to_string()))?;
}
Ok(())
}
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
pub struct NativeTopology;
#[cfg(not(any(target_os = "windows", target_os = "linux")))]
#[async_trait::async_trait]
impl traits::UniversalTopology for NativeTopology {
fn acquire() -> DisplayResult<Self> {
Err(DisplayError::UnsupportedFeature("Platform not supported".into()))
}
fn get_outputs(&self) -> Vec<OutputState> {
vec![]
}
fn edit_output(&mut self, _: &DisplayId) -> DisplayResult<Box<dyn OutputEditable + '_>> {
Err(DisplayError::UnsupportedFeature("Platform not supported".into()))
}
fn set_persistence(&mut self, _: bool) -> &mut Self {
self
}
async fn validate(&self) -> DisplayResult<()> {
Ok(())
}
async fn commit(&mut self) -> DisplayResult<()> {
Ok(())
}
}