1use {
4 crate::{
5 video::connector_type::{
6 ConnectorType, CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI,
7 CON_DSI, CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA,
8 CON_HDMIB, CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA,
9 CON_VIRTUAL, CON_WRITEBACK,
10 },
11 PciId,
12 _private::WireMode,
13 },
14 serde::{Deserialize, Serialize},
15 std::{str::FromStr, time::Duration},
16};
17
18#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
26pub struct Mode {
27 pub(crate) width: i32,
28 pub(crate) height: i32,
29 pub(crate) refresh_millihz: u32,
30}
31
32impl Mode {
33 pub fn width(&self) -> i32 {
35 self.width
36 }
37
38 pub fn height(&self) -> i32 {
40 self.height
41 }
42
43 pub fn refresh_rate(&self) -> u32 {
47 self.refresh_millihz
48 }
49
50 pub(crate) fn zeroed() -> Self {
51 Self {
52 width: 0,
53 height: 0,
54 refresh_millihz: 0,
55 }
56 }
57}
58
59#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
64pub struct Connector(pub u64);
65
66impl Connector {
67 pub fn exists(self) -> bool {
72 self.0 != 0
73 }
74
75 pub fn connected(self) -> bool {
77 if !self.exists() {
78 return false;
79 }
80 get!(false).connector_connected(self)
81 }
82
83 pub fn scale(self) -> f64 {
85 if !self.exists() {
86 return 1.0;
87 }
88 get!(1.0).connector_get_scale(self)
89 }
90
91 pub fn set_scale(self, scale: f64) {
93 if !self.exists() {
94 return;
95 }
96 log::info!("setting scale to {}", scale);
97 get!().connector_set_scale(self, scale);
98 }
99
100 pub fn ty(self) -> ConnectorType {
102 if !self.exists() {
103 return CON_UNKNOWN;
104 }
105 get!(CON_UNKNOWN).connector_type(self)
106 }
107
108 pub fn mode(self) -> Mode {
110 if !self.exists() {
111 return Mode::zeroed();
112 }
113 get!(Mode::zeroed()).connector_mode(self)
114 }
115
116 pub fn set_mode(self, width: i32, height: i32, refresh_millihz: Option<u32>) {
124 if !self.exists() {
125 log::warn!("set_mode called on a connector that does not exist");
126 return;
127 }
128 let refresh_millihz = match refresh_millihz {
129 Some(r) => r,
130 _ => match self
131 .modes()
132 .iter()
133 .find(|m| m.width == width && m.height == height)
134 {
135 Some(m) => m.refresh_millihz,
136 _ => {
137 log::warn!("Could not find any mode with width {width} and height {height}");
138 return;
139 }
140 },
141 };
142 get!().connector_set_mode(
143 self,
144 WireMode {
145 width,
146 height,
147 refresh_millihz,
148 },
149 )
150 }
151
152 pub fn modes(self) -> Vec<Mode> {
154 if !self.exists() {
155 return Vec::new();
156 }
157 get!(Vec::new()).connector_modes(self)
158 }
159
160 pub fn width(self) -> i32 {
164 get!().connector_size(self).0
165 }
166
167 pub fn height(self) -> i32 {
171 get!().connector_size(self).1
172 }
173
174 pub fn refresh_rate(self) -> u32 {
178 self.mode().refresh_millihz
179 }
180
181 pub fn position(self) -> (i32, i32) {
183 if !self.connected() {
184 return (0, 0);
185 }
186 get!().connector_get_position(self)
187 }
188
189 pub fn set_position(self, x: i32, y: i32) {
197 if !self.exists() {
198 log::warn!("set_position called on a connector that does not exist");
199 return;
200 }
201 get!().connector_set_position(self, x, y);
202 }
203
204 pub fn set_enabled(self, enabled: bool) {
208 if !self.exists() {
209 log::warn!("set_enabled called on a connector that does not exist");
210 return;
211 }
212 get!().connector_set_enabled(self, enabled);
213 }
214
215 pub fn set_transform(self, transform: Transform) {
217 if !self.exists() {
218 log::warn!("set_transform called on a connector that does not exist");
219 return;
220 }
221 get!().connector_set_transform(self, transform);
222 }
223
224 pub fn name(self) -> String {
225 if !self.exists() {
226 return String::new();
227 }
228 get!(String::new()).connector_get_name(self)
229 }
230
231 pub fn model(self) -> String {
232 if !self.exists() {
233 return String::new();
234 }
235 get!(String::new()).connector_get_model(self)
236 }
237
238 pub fn manufacturer(self) -> String {
239 if !self.exists() {
240 return String::new();
241 }
242 get!(String::new()).connector_get_manufacturer(self)
243 }
244
245 pub fn serial_number(self) -> String {
246 if !self.exists() {
247 return String::new();
248 }
249 get!(String::new()).connector_get_serial_number(self)
250 }
251
252 pub fn set_vrr_mode(self, mode: VrrMode) {
254 get!().set_vrr_mode(Some(self), mode)
255 }
256
257 pub fn set_vrr_cursor_hz(self, hz: f64) {
263 get!().set_vrr_cursor_hz(Some(self), hz)
264 }
265
266 pub fn set_tearing_mode(self, mode: TearingMode) {
268 get!().set_tearing_mode(Some(self), mode)
269 }
270
271 pub fn set_format(self, format: Format) {
273 get!().connector_set_format(self, format);
274 }
275}
276
277pub fn drm_devices() -> Vec<DrmDevice> {
279 get!().drm_devices()
280}
281
282pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
284 get!().on_new_drm_device(f)
285}
286
287pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
289 get!().on_del_drm_device(f)
290}
291
292pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
294 get!().on_new_connector(f)
295}
296
297pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
299 get!().on_connector_connected(f)
300}
301
302pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
304 get!().on_connector_disconnected(f)
305}
306
307pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
312 get!().on_graphics_initialized(f)
313}
314
315pub fn connectors() -> Vec<Connector> {
316 get!().connectors(None)
317}
318
319pub fn get_connector(id: impl ToConnectorId) -> Connector {
353 let (ty, idx) = match id.to_connector_id() {
354 Ok(id) => id,
355 Err(e) => {
356 log::error!("{}", e);
357 return Connector(0);
358 }
359 };
360 get!(Connector(0)).get_connector(ty, idx)
361}
362
363pub trait ToConnectorId {
365 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
366}
367
368impl ToConnectorId for (ConnectorType, u32) {
369 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
370 Ok(*self)
371 }
372}
373
374impl ToConnectorId for &'_ str {
375 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
376 let pairs = [
377 ("DP-", CON_DISPLAY_PORT),
378 ("eDP-", CON_EDP),
379 ("HDMI-A-", CON_HDMIA),
380 ("HDMI-B-", CON_HDMIB),
381 ("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
382 ("VGA-", CON_VGA),
383 ("DVI-I-", CON_DVII),
384 ("DVI-D-", CON_DVID),
385 ("DVI-A-", CON_DVIA),
386 ("Composite-", CON_COMPOSITE),
387 ("SVIDEO-", CON_SVIDEO),
388 ("LVDS-", CON_LVDS),
389 ("Component-", CON_COMPONENT),
390 ("DIN-", CON_9PIN_DIN),
391 ("TV-", CON_TV),
392 ("Virtual-", CON_VIRTUAL),
393 ("DSI-", CON_DSI),
394 ("DPI-", CON_DPI),
395 ("Writeback-", CON_WRITEBACK),
396 ("SPI-", CON_SPI),
397 ("USB-", CON_USB),
398 ];
399 for (prefix, ty) in pairs {
400 if let Some(suffix) = self.strip_prefix(prefix) {
401 if let Ok(idx) = u32::from_str(suffix) {
402 return Ok((ty, idx));
403 }
404 }
405 }
406 Err(format!("`{}` is not a valid connector identifier", self))
407 }
408}
409
410pub mod connector_type {
412 use serde::{Deserialize, Serialize};
413
414 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
416 pub struct ConnectorType(pub u32);
417
418 pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
419 pub const CON_VGA: ConnectorType = ConnectorType(1);
420 pub const CON_DVII: ConnectorType = ConnectorType(2);
421 pub const CON_DVID: ConnectorType = ConnectorType(3);
422 pub const CON_DVIA: ConnectorType = ConnectorType(4);
423 pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
424 pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
425 pub const CON_LVDS: ConnectorType = ConnectorType(7);
426 pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
427 pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
428 pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
429 pub const CON_HDMIA: ConnectorType = ConnectorType(11);
430 pub const CON_HDMIB: ConnectorType = ConnectorType(12);
431 pub const CON_TV: ConnectorType = ConnectorType(13);
432 pub const CON_EDP: ConnectorType = ConnectorType(14);
433 pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
434 pub const CON_DSI: ConnectorType = ConnectorType(16);
435 pub const CON_DPI: ConnectorType = ConnectorType(17);
436 pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
437 pub const CON_SPI: ConnectorType = ConnectorType(19);
438 pub const CON_USB: ConnectorType = ConnectorType(20);
439 pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
440}
441
442#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
448pub struct DrmDevice(pub u64);
449
450impl DrmDevice {
451 pub fn connectors(self) -> Vec<Connector> {
453 get!().connectors(Some(self))
454 }
455
456 pub fn devnode(self) -> String {
460 get!().drm_device_devnode(self)
461 }
462
463 pub fn syspath(self) -> String {
467 get!().drm_device_syspath(self)
468 }
469
470 pub fn vendor(self) -> String {
474 get!().drm_device_vendor(self)
475 }
476
477 pub fn model(self) -> String {
481 get!().drm_device_model(self)
482 }
483
484 pub fn pci_id(self) -> PciId {
488 get!().drm_device_pci_id(self)
489 }
490
491 pub fn make_render_device(self) {
493 get!().make_render_device(self);
494 }
495
496 pub fn set_gfx_api(self, gfx_api: GfxApi) {
500 get!().set_gfx_api(Some(self), gfx_api);
501 }
502
503 pub fn set_direct_scanout_enabled(self, enabled: bool) {
505 get!().set_direct_scanout_enabled(Some(self), enabled);
506 }
507
508 pub fn set_flip_margin(self, margin: Duration) {
515 get!().set_flip_margin(self, margin);
516 }
517}
518
519#[non_exhaustive]
521#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
522pub enum GfxApi {
523 OpenGl,
524 Vulkan,
525}
526
527pub fn set_gfx_api(gfx_api: GfxApi) {
535 get!().set_gfx_api(None, gfx_api);
536}
537
538pub fn set_direct_scanout_enabled(enabled: bool) {
544 get!().set_direct_scanout_enabled(None, enabled);
545}
546
547#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
549pub enum Transform {
550 #[default]
552 None,
553 Rotate90,
555 Rotate180,
557 Rotate270,
559 Flip,
561 FlipRotate90,
563 FlipRotate180,
565 FlipRotate270,
567}
568
569#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
571pub struct VrrMode(pub u32);
572
573impl VrrMode {
574 pub const NEVER: Self = Self(0);
576 pub const ALWAYS: Self = Self(1);
578 pub const VARIANT_1: Self = Self(2);
580 pub const VARIANT_2: Self = Self(3);
582 pub const VARIANT_3: Self = Self(4);
584}
585
586pub fn set_vrr_mode(mode: VrrMode) {
590 get!().set_vrr_mode(None, mode)
591}
592
593pub fn set_vrr_cursor_hz(hz: f64) {
601 get!().set_vrr_cursor_hz(None, hz)
602}
603
604#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
606pub struct TearingMode(pub u32);
607
608impl TearingMode {
609 pub const NEVER: Self = Self(0);
611 pub const ALWAYS: Self = Self(1);
613 pub const VARIANT_1: Self = Self(2);
615 pub const VARIANT_2: Self = Self(3);
617 pub const VARIANT_3: Self = Self(4);
622}
623
624pub fn set_tearing_mode(mode: TearingMode) {
628 get!().set_tearing_mode(None, mode)
629}
630
631#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
633pub struct Format(pub u32);
634
635impl Format {
636 pub const ARGB8888: Self = Self(0);
637 pub const XRGB8888: Self = Self(1);
638 pub const ABGR8888: Self = Self(2);
639 pub const XBGR8888: Self = Self(3);
640 pub const R8: Self = Self(4);
641 pub const GR88: Self = Self(5);
642 pub const RGB888: Self = Self(6);
643 pub const BGR888: Self = Self(7);
644 pub const RGBA4444: Self = Self(8);
645 pub const RGBX4444: Self = Self(9);
646 pub const BGRA4444: Self = Self(10);
647 pub const BGRX4444: Self = Self(11);
648 pub const RGB565: Self = Self(12);
649 pub const BGR565: Self = Self(13);
650 pub const RGBA5551: Self = Self(14);
651 pub const RGBX5551: Self = Self(15);
652 pub const BGRA5551: Self = Self(16);
653 pub const BGRX5551: Self = Self(17);
654 pub const ARGB1555: Self = Self(18);
655 pub const XRGB1555: Self = Self(19);
656 pub const ARGB2101010: Self = Self(20);
657 pub const XRGB2101010: Self = Self(21);
658 pub const ABGR2101010: Self = Self(22);
659 pub const XBGR2101010: Self = Self(23);
660 pub const ABGR16161616: Self = Self(24);
661 pub const XBGR16161616: Self = Self(25);
662 pub const ABGR16161616F: Self = Self(26);
663 pub const XBGR16161616F: Self = Self(27);
664}