use {
crate::{
_private::WireMode,
Direction, PciId, Workspace,
video::connector_type::{
CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, CON_DSI,
CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB,
CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA, CON_VIRTUAL,
CON_WRITEBACK, ConnectorType,
},
},
serde::{Deserialize, Serialize},
std::{str::FromStr, time::Duration},
};
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Mode {
pub(crate) width: i32,
pub(crate) height: i32,
pub(crate) refresh_millihz: u32,
}
impl Mode {
pub fn width(&self) -> i32 {
self.width
}
pub fn height(&self) -> i32 {
self.height
}
pub fn refresh_rate(&self) -> u32 {
self.refresh_millihz
}
pub(crate) fn zeroed() -> Self {
Self {
width: 0,
height: 0,
refresh_millihz: 0,
}
}
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct Connector(pub u64);
impl Connector {
pub fn exists(self) -> bool {
self.0 != 0
}
pub fn connected(self) -> bool {
if !self.exists() {
return false;
}
get!(false).connector_connected(self)
}
pub fn scale(self) -> f64 {
if !self.exists() {
return 1.0;
}
get!(1.0).connector_get_scale(self)
}
pub fn set_scale(self, scale: f64) {
if !self.exists() {
return;
}
log::info!("setting scale to {}", scale);
get!().connector_set_scale(self, scale);
}
pub fn ty(self) -> ConnectorType {
if !self.exists() {
return CON_UNKNOWN;
}
get!(CON_UNKNOWN).connector_type(self)
}
pub fn mode(self) -> Mode {
if !self.exists() {
return Mode::zeroed();
}
get!(Mode::zeroed()).connector_mode(self)
}
pub fn set_mode(self, width: i32, height: i32, refresh_millihz: Option<u32>) {
if !self.exists() {
log::warn!("set_mode called on a connector that does not exist");
return;
}
let refresh_millihz = match refresh_millihz {
Some(r) => r,
_ => match self
.modes()
.iter()
.find(|m| m.width == width && m.height == height)
{
Some(m) => m.refresh_millihz,
_ => {
log::warn!("Could not find any mode with width {width} and height {height}");
return;
}
},
};
get!().connector_set_mode(
self,
WireMode {
width,
height,
refresh_millihz,
},
)
}
pub fn modes(self) -> Vec<Mode> {
if !self.exists() {
return Vec::new();
}
get!(Vec::new()).connector_modes(self)
}
pub fn width(self) -> i32 {
get!().connector_size(self).0
}
pub fn height(self) -> i32 {
get!().connector_size(self).1
}
pub fn refresh_rate(self) -> u32 {
self.mode().refresh_millihz
}
pub fn position(self) -> (i32, i32) {
if !self.connected() {
return (0, 0);
}
get!().connector_get_position(self)
}
pub fn set_position(self, x: i32, y: i32) {
if !self.exists() {
log::warn!("set_position called on a connector that does not exist");
return;
}
get!().connector_set_position(self, x, y);
}
pub fn set_enabled(self, enabled: bool) {
if !self.exists() {
log::warn!("set_enabled called on a connector that does not exist");
return;
}
get!().connector_set_enabled(self, enabled);
}
pub fn set_transform(self, transform: Transform) {
if !self.exists() {
log::warn!("set_transform called on a connector that does not exist");
return;
}
get!().connector_set_transform(self, transform);
}
pub fn name(self) -> String {
if !self.exists() {
return String::new();
}
get!(String::new()).connector_get_name(self)
}
pub fn model(self) -> String {
if !self.exists() {
return String::new();
}
get!(String::new()).connector_get_model(self)
}
pub fn manufacturer(self) -> String {
if !self.exists() {
return String::new();
}
get!(String::new()).connector_get_manufacturer(self)
}
pub fn serial_number(self) -> String {
if !self.exists() {
return String::new();
}
get!(String::new()).connector_get_serial_number(self)
}
pub fn set_vrr_mode(self, mode: VrrMode) {
get!().set_vrr_mode(Some(self), mode)
}
pub fn set_vrr_cursor_hz(self, hz: f64) {
get!().set_vrr_cursor_hz(Some(self), hz)
}
pub fn set_tearing_mode(self, mode: TearingMode) {
get!().set_tearing_mode(Some(self), mode)
}
pub fn set_format(self, format: Format) {
get!().connector_set_format(self, format);
}
pub fn set_colors(self, color_space: ColorSpace, eotf: Eotf) {
get!().connector_set_colors(self, color_space, eotf);
}
pub fn set_blend_space(self, blend_space: BlendSpace) {
get!().connector_set_blend_space(self, blend_space);
}
pub fn set_brightness(self, brightness: Option<f64>) {
get!().connector_set_brightness(self, brightness);
}
pub fn active_workspace(self) -> Workspace {
get!(Workspace(0)).get_connector_active_workspace(self)
}
pub fn workspaces(self) -> Vec<Workspace> {
get!().get_connector_workspaces(self)
}
pub fn connector_in_direction(self, direction: Direction) -> Connector {
get!(Connector(0)).get_connector_in_direction(self, direction)
}
pub fn set_use_native_gamut(self, use_native_gamut: bool) {
get!().connector_set_use_native_gamut(self, use_native_gamut);
}
}
pub fn drm_devices() -> Vec<DrmDevice> {
get!().drm_devices()
}
pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
get!().on_new_drm_device(f)
}
pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
get!().on_del_drm_device(f)
}
pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
get!().on_new_connector(f)
}
pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
get!().on_connector_connected(f)
}
pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
get!().on_connector_disconnected(f)
}
pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
get!().on_graphics_initialized(f)
}
pub fn connectors() -> Vec<Connector> {
get!().connectors(None)
}
pub fn get_connector(id: impl ToConnectorId) -> Connector {
let (ty, idx) = match id.to_connector_id() {
Ok(id) => id,
Err(e) => {
log::error!("{}", e);
return Connector(0);
}
};
get!(Connector(0)).get_connector(ty, idx)
}
pub trait ToConnectorId {
fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
}
impl ToConnectorId for (ConnectorType, u32) {
fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
Ok(*self)
}
}
impl ToConnectorId for &'_ str {
fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
let pairs = [
("DP-", CON_DISPLAY_PORT),
("eDP-", CON_EDP),
("HDMI-A-", CON_HDMIA),
("HDMI-B-", CON_HDMIB),
("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
("VGA-", CON_VGA),
("DVI-I-", CON_DVII),
("DVI-D-", CON_DVID),
("DVI-A-", CON_DVIA),
("Composite-", CON_COMPOSITE),
("SVIDEO-", CON_SVIDEO),
("LVDS-", CON_LVDS),
("Component-", CON_COMPONENT),
("DIN-", CON_9PIN_DIN),
("TV-", CON_TV),
("Virtual-", CON_VIRTUAL),
("DSI-", CON_DSI),
("DPI-", CON_DPI),
("Writeback-", CON_WRITEBACK),
("SPI-", CON_SPI),
("USB-", CON_USB),
];
for (prefix, ty) in pairs {
if let Some(suffix) = self.strip_prefix(prefix)
&& let Ok(idx) = u32::from_str(suffix)
{
return Ok((ty, idx));
}
}
Err(format!("`{}` is not a valid connector identifier", self))
}
}
pub mod connector_type {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct ConnectorType(pub u32);
pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
pub const CON_VGA: ConnectorType = ConnectorType(1);
pub const CON_DVII: ConnectorType = ConnectorType(2);
pub const CON_DVID: ConnectorType = ConnectorType(3);
pub const CON_DVIA: ConnectorType = ConnectorType(4);
pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
pub const CON_LVDS: ConnectorType = ConnectorType(7);
pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
pub const CON_HDMIA: ConnectorType = ConnectorType(11);
pub const CON_HDMIB: ConnectorType = ConnectorType(12);
pub const CON_TV: ConnectorType = ConnectorType(13);
pub const CON_EDP: ConnectorType = ConnectorType(14);
pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
pub const CON_DSI: ConnectorType = ConnectorType(16);
pub const CON_DPI: ConnectorType = ConnectorType(17);
pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
pub const CON_SPI: ConnectorType = ConnectorType(19);
pub const CON_USB: ConnectorType = ConnectorType(20);
pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub struct DrmDevice(pub u64);
impl DrmDevice {
pub fn connectors(self) -> Vec<Connector> {
get!().connectors(Some(self))
}
pub fn devnode(self) -> String {
get!().drm_device_devnode(self)
}
pub fn syspath(self) -> String {
get!().drm_device_syspath(self)
}
pub fn vendor(self) -> String {
get!().drm_device_vendor(self)
}
pub fn model(self) -> String {
get!().drm_device_model(self)
}
pub fn pci_id(self) -> PciId {
get!().drm_device_pci_id(self)
}
pub fn make_render_device(self) {
get!().make_render_device(self);
}
pub fn set_gfx_api(self, gfx_api: GfxApi) {
get!().set_gfx_api(Some(self), gfx_api);
}
pub fn set_direct_scanout_enabled(self, enabled: bool) {
get!().set_direct_scanout_enabled(Some(self), enabled);
}
pub fn set_flip_margin(self, margin: Duration) {
get!().set_flip_margin(self, margin);
}
}
#[non_exhaustive]
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum GfxApi {
OpenGl,
Vulkan,
}
pub fn set_gfx_api(gfx_api: GfxApi) {
get!().set_gfx_api(None, gfx_api);
}
pub fn set_direct_scanout_enabled(enabled: bool) {
get!().set_direct_scanout_enabled(None, enabled);
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub enum Transform {
#[default]
None,
Rotate90,
Rotate180,
Rotate270,
Flip,
FlipRotate90,
FlipRotate180,
FlipRotate270,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct VrrMode(pub u32);
impl VrrMode {
pub const NEVER: Self = Self(0);
pub const ALWAYS: Self = Self(1);
pub const VARIANT_1: Self = Self(2);
pub const VARIANT_2: Self = Self(3);
pub const VARIANT_3: Self = Self(4);
}
pub fn set_vrr_mode(mode: VrrMode) {
get!().set_vrr_mode(None, mode)
}
pub fn set_vrr_cursor_hz(hz: f64) {
get!().set_vrr_cursor_hz(None, hz)
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
pub struct TearingMode(pub u32);
impl TearingMode {
pub const NEVER: Self = Self(0);
pub const ALWAYS: Self = Self(1);
pub const VARIANT_1: Self = Self(2);
pub const VARIANT_2: Self = Self(3);
pub const VARIANT_3: Self = Self(4);
}
pub fn set_tearing_mode(mode: TearingMode) {
get!().set_tearing_mode(None, mode)
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Format(pub u32);
impl Format {
pub const ARGB8888: Self = Self(0);
pub const XRGB8888: Self = Self(1);
pub const ABGR8888: Self = Self(2);
pub const XBGR8888: Self = Self(3);
pub const R8: Self = Self(4);
pub const GR88: Self = Self(5);
pub const RGB888: Self = Self(6);
pub const BGR888: Self = Self(7);
pub const RGBA4444: Self = Self(8);
pub const RGBX4444: Self = Self(9);
pub const BGRA4444: Self = Self(10);
pub const BGRX4444: Self = Self(11);
pub const RGB565: Self = Self(12);
pub const BGR565: Self = Self(13);
pub const RGBA5551: Self = Self(14);
pub const RGBX5551: Self = Self(15);
pub const BGRA5551: Self = Self(16);
pub const BGRX5551: Self = Self(17);
pub const ARGB1555: Self = Self(18);
pub const XRGB1555: Self = Self(19);
pub const ARGB2101010: Self = Self(20);
pub const XRGB2101010: Self = Self(21);
pub const ABGR2101010: Self = Self(22);
pub const XBGR2101010: Self = Self(23);
pub const ABGR16161616: Self = Self(24);
pub const XBGR16161616: Self = Self(25);
pub const ABGR16161616F: Self = Self(26);
pub const XBGR16161616F: Self = Self(27);
pub const BGR161616: Self = Self(28);
pub const R16F: Self = Self(29);
pub const GR1616F: Self = Self(30);
pub const BGR161616F: Self = Self(31);
pub const R32F: Self = Self(32);
pub const GR3232F: Self = Self(33);
pub const BGR323232F: Self = Self(34);
pub const ABGR32323232F: Self = Self(35);
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct ColorSpace(pub u32);
impl ColorSpace {
pub const DEFAULT: Self = Self(0);
pub const BT2020: Self = Self(1);
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct Eotf(pub u32);
#[deprecated = "use the Eotf type instead"]
pub type TransferFunction = Eotf;
impl Eotf {
pub const DEFAULT: Self = Self(0);
pub const PQ: Self = Self(1);
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct BlendSpace(pub u32);
impl BlendSpace {
pub const SRGB: Self = Self(0);
pub const LINEAR: Self = Self(1);
}