use smithay::{ backend::drm::VrrSupport as Support, output::{Output, WeakOutput}, utils::{Rectangle, Transform}, }; pub use super::geometry::*; use crate::config::{AdaptiveSync, OutputConfig, OutputState}; pub use crate::shell::{SeatExt, Shell, Workspace}; pub use crate::state::{Common, State}; pub use crate::wayland::handlers::xdg_shell::popup::update_reactive_popups; use std::{ cell::{Ref, RefCell, RefMut}, sync::{ atomic::{AtomicU8, Ordering}, Mutex, }, }; pub trait OutputExt { fn geometry(&self) -> Rectangle; fn adaptive_sync(&self) -> AdaptiveSync; fn set_adaptive_sync(&self, vrr: AdaptiveSync); fn adaptive_sync_support(&self) -> Option; fn set_adaptive_sync_support(&self, vrr: Option); fn mirroring(&self) -> Option; fn set_mirroring(&self, output: Option); fn is_enabled(&self) -> bool; fn config(&self) -> Ref<'_, OutputConfig>; fn config_mut(&self) -> RefMut<'_, OutputConfig>; } struct Vrr(AtomicU8); struct VrrSupport(AtomicU8); struct Mirroring(Mutex>); impl OutputExt for Output { fn geometry(&self) -> Rectangle { Rectangle::from_loc_and_size(self.current_location(), { Transform::from(self.current_transform()) .transform_size( self.current_mode() .map(|m| m.size) .unwrap_or_else(|| (0, 0).into()), ) .to_f64() .to_logical(self.current_scale().fractional_scale()) .to_i32_round() }) .as_global() } fn adaptive_sync(&self) -> AdaptiveSync { self.user_data() .get::() .map(|vrr| match vrr.0.load(Ordering::SeqCst) { 2 => AdaptiveSync::Force, 1 => AdaptiveSync::Enabled, _ => AdaptiveSync::Disabled, }) .unwrap_or(AdaptiveSync::Disabled) } fn set_adaptive_sync(&self, vrr: AdaptiveSync) { let user_data = self.user_data(); user_data.insert_if_missing_threadsafe(|| Vrr(AtomicU8::new(0))); user_data.get::().unwrap().0.store( match vrr { AdaptiveSync::Disabled => 0, AdaptiveSync::Enabled => 1, AdaptiveSync::Force => 2, }, Ordering::SeqCst, ); } fn adaptive_sync_support(&self) -> Option { self.user_data() .get::() .map(|vrr| match vrr.0.load(Ordering::SeqCst) { 0 => None, 2 => Some(Support::RequiresModeset), 3 => Some(Support::Supported), _ => Some(Support::NotSupported), }) .flatten() } fn set_adaptive_sync_support(&self, vrr: Option) { let user_data = self.user_data(); user_data.insert_if_missing_threadsafe(|| VrrSupport(AtomicU8::new(0))); user_data.get::().unwrap().0.store( match vrr { None => 0, Some(Support::NotSupported) => 1, Some(Support::RequiresModeset) => 2, Some(Support::Supported) => 3, }, Ordering::SeqCst, ); } fn mirroring(&self) -> Option { self.user_data().get::().and_then(|mirroring| { mirroring .0 .lock() .unwrap() .clone() .and_then(|o| o.upgrade()) }) } fn set_mirroring(&self, output: Option) { let user_data = self.user_data(); user_data.insert_if_missing_threadsafe(|| Mirroring(Mutex::new(None))); *user_data.get::().unwrap().0.lock().unwrap() = output.map(|output| output.downgrade()); } fn is_enabled(&self) -> bool { self.user_data() .get::>() .map(|conf| conf.borrow().enabled != OutputState::Disabled) .unwrap_or(false) } fn config(&self) -> Ref<'_, OutputConfig> { self.user_data() .get::>() .unwrap() .borrow() } fn config_mut(&self) -> RefMut<'_, OutputConfig> { self.user_data() .get::>() .unwrap() .borrow_mut() } }