1use {
4 crate::{
5 _private::WireMode,
6 PciId, Workspace,
7 video::connector_type::{
8 CON_9PIN_DIN, CON_COMPONENT, CON_COMPOSITE, CON_DISPLAY_PORT, CON_DPI, CON_DSI,
9 CON_DVIA, CON_DVID, CON_DVII, CON_EDP, CON_EMBEDDED_WINDOW, CON_HDMIA, CON_HDMIB,
10 CON_LVDS, CON_SPI, CON_SVIDEO, CON_TV, CON_UNKNOWN, CON_USB, CON_VGA, CON_VIRTUAL,
11 CON_WRITEBACK, ConnectorType,
12 },
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 pub fn set_colors(self, color_space: ColorSpace, transfer_function: TransferFunction) {
286 get!().connector_set_colors(self, color_space, transfer_function);
287 }
288
289 pub fn set_brightness(self, brightness: Option<f64>) {
302 get!().connector_set_brightness(self, brightness);
303 }
304
305 pub fn active_workspace(self) -> Workspace {
310 get!(Workspace(0)).get_connector_active_workspace(self)
311 }
312
313 pub fn workspaces(self) -> Vec<Workspace> {
317 get!().get_connector_workspaces(self)
318 }
319}
320
321pub fn drm_devices() -> Vec<DrmDevice> {
323 get!().drm_devices()
324}
325
326pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
328 get!().on_new_drm_device(f)
329}
330
331pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
333 get!().on_del_drm_device(f)
334}
335
336pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
338 get!().on_new_connector(f)
339}
340
341pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
343 get!().on_connector_connected(f)
344}
345
346pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
348 get!().on_connector_disconnected(f)
349}
350
351pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
356 get!().on_graphics_initialized(f)
357}
358
359pub fn connectors() -> Vec<Connector> {
360 get!().connectors(None)
361}
362
363pub fn get_connector(id: impl ToConnectorId) -> Connector {
397 let (ty, idx) = match id.to_connector_id() {
398 Ok(id) => id,
399 Err(e) => {
400 log::error!("{}", e);
401 return Connector(0);
402 }
403 };
404 get!(Connector(0)).get_connector(ty, idx)
405}
406
407pub trait ToConnectorId {
409 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
410}
411
412impl ToConnectorId for (ConnectorType, u32) {
413 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
414 Ok(*self)
415 }
416}
417
418impl ToConnectorId for &'_ str {
419 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
420 let pairs = [
421 ("DP-", CON_DISPLAY_PORT),
422 ("eDP-", CON_EDP),
423 ("HDMI-A-", CON_HDMIA),
424 ("HDMI-B-", CON_HDMIB),
425 ("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
426 ("VGA-", CON_VGA),
427 ("DVI-I-", CON_DVII),
428 ("DVI-D-", CON_DVID),
429 ("DVI-A-", CON_DVIA),
430 ("Composite-", CON_COMPOSITE),
431 ("SVIDEO-", CON_SVIDEO),
432 ("LVDS-", CON_LVDS),
433 ("Component-", CON_COMPONENT),
434 ("DIN-", CON_9PIN_DIN),
435 ("TV-", CON_TV),
436 ("Virtual-", CON_VIRTUAL),
437 ("DSI-", CON_DSI),
438 ("DPI-", CON_DPI),
439 ("Writeback-", CON_WRITEBACK),
440 ("SPI-", CON_SPI),
441 ("USB-", CON_USB),
442 ];
443 for (prefix, ty) in pairs {
444 if let Some(suffix) = self.strip_prefix(prefix)
445 && let Ok(idx) = u32::from_str(suffix)
446 {
447 return Ok((ty, idx));
448 }
449 }
450 Err(format!("`{}` is not a valid connector identifier", self))
451 }
452}
453
454pub mod connector_type {
456 use serde::{Deserialize, Serialize};
457
458 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
460 pub struct ConnectorType(pub u32);
461
462 pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
463 pub const CON_VGA: ConnectorType = ConnectorType(1);
464 pub const CON_DVII: ConnectorType = ConnectorType(2);
465 pub const CON_DVID: ConnectorType = ConnectorType(3);
466 pub const CON_DVIA: ConnectorType = ConnectorType(4);
467 pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
468 pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
469 pub const CON_LVDS: ConnectorType = ConnectorType(7);
470 pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
471 pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
472 pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
473 pub const CON_HDMIA: ConnectorType = ConnectorType(11);
474 pub const CON_HDMIB: ConnectorType = ConnectorType(12);
475 pub const CON_TV: ConnectorType = ConnectorType(13);
476 pub const CON_EDP: ConnectorType = ConnectorType(14);
477 pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
478 pub const CON_DSI: ConnectorType = ConnectorType(16);
479 pub const CON_DPI: ConnectorType = ConnectorType(17);
480 pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
481 pub const CON_SPI: ConnectorType = ConnectorType(19);
482 pub const CON_USB: ConnectorType = ConnectorType(20);
483 pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
484}
485
486#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
492pub struct DrmDevice(pub u64);
493
494impl DrmDevice {
495 pub fn connectors(self) -> Vec<Connector> {
497 get!().connectors(Some(self))
498 }
499
500 pub fn devnode(self) -> String {
504 get!().drm_device_devnode(self)
505 }
506
507 pub fn syspath(self) -> String {
511 get!().drm_device_syspath(self)
512 }
513
514 pub fn vendor(self) -> String {
518 get!().drm_device_vendor(self)
519 }
520
521 pub fn model(self) -> String {
525 get!().drm_device_model(self)
526 }
527
528 pub fn pci_id(self) -> PciId {
532 get!().drm_device_pci_id(self)
533 }
534
535 pub fn make_render_device(self) {
537 get!().make_render_device(self);
538 }
539
540 pub fn set_gfx_api(self, gfx_api: GfxApi) {
544 get!().set_gfx_api(Some(self), gfx_api);
545 }
546
547 pub fn set_direct_scanout_enabled(self, enabled: bool) {
549 get!().set_direct_scanout_enabled(Some(self), enabled);
550 }
551
552 pub fn set_flip_margin(self, margin: Duration) {
559 get!().set_flip_margin(self, margin);
560 }
561}
562
563#[non_exhaustive]
565#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
566pub enum GfxApi {
567 OpenGl,
568 Vulkan,
569}
570
571pub fn set_gfx_api(gfx_api: GfxApi) {
579 get!().set_gfx_api(None, gfx_api);
580}
581
582pub fn set_direct_scanout_enabled(enabled: bool) {
588 get!().set_direct_scanout_enabled(None, enabled);
589}
590
591#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
593pub enum Transform {
594 #[default]
596 None,
597 Rotate90,
599 Rotate180,
601 Rotate270,
603 Flip,
605 FlipRotate90,
607 FlipRotate180,
609 FlipRotate270,
611}
612
613#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
615pub struct VrrMode(pub u32);
616
617impl VrrMode {
618 pub const NEVER: Self = Self(0);
620 pub const ALWAYS: Self = Self(1);
622 pub const VARIANT_1: Self = Self(2);
624 pub const VARIANT_2: Self = Self(3);
626 pub const VARIANT_3: Self = Self(4);
628}
629
630pub fn set_vrr_mode(mode: VrrMode) {
634 get!().set_vrr_mode(None, mode)
635}
636
637pub fn set_vrr_cursor_hz(hz: f64) {
645 get!().set_vrr_cursor_hz(None, hz)
646}
647
648#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
650pub struct TearingMode(pub u32);
651
652impl TearingMode {
653 pub const NEVER: Self = Self(0);
655 pub const ALWAYS: Self = Self(1);
657 pub const VARIANT_1: Self = Self(2);
659 pub const VARIANT_2: Self = Self(3);
661 pub const VARIANT_3: Self = Self(4);
666}
667
668pub fn set_tearing_mode(mode: TearingMode) {
672 get!().set_tearing_mode(None, mode)
673}
674
675#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
677pub struct Format(pub u32);
678
679impl Format {
680 pub const ARGB8888: Self = Self(0);
681 pub const XRGB8888: Self = Self(1);
682 pub const ABGR8888: Self = Self(2);
683 pub const XBGR8888: Self = Self(3);
684 pub const R8: Self = Self(4);
685 pub const GR88: Self = Self(5);
686 pub const RGB888: Self = Self(6);
687 pub const BGR888: Self = Self(7);
688 pub const RGBA4444: Self = Self(8);
689 pub const RGBX4444: Self = Self(9);
690 pub const BGRA4444: Self = Self(10);
691 pub const BGRX4444: Self = Self(11);
692 pub const RGB565: Self = Self(12);
693 pub const BGR565: Self = Self(13);
694 pub const RGBA5551: Self = Self(14);
695 pub const RGBX5551: Self = Self(15);
696 pub const BGRA5551: Self = Self(16);
697 pub const BGRX5551: Self = Self(17);
698 pub const ARGB1555: Self = Self(18);
699 pub const XRGB1555: Self = Self(19);
700 pub const ARGB2101010: Self = Self(20);
701 pub const XRGB2101010: Self = Self(21);
702 pub const ABGR2101010: Self = Self(22);
703 pub const XBGR2101010: Self = Self(23);
704 pub const ABGR16161616: Self = Self(24);
705 pub const XBGR16161616: Self = Self(25);
706 pub const ABGR16161616F: Self = Self(26);
707 pub const XBGR16161616F: Self = Self(27);
708}
709
710#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
712pub struct ColorSpace(pub u32);
713
714impl ColorSpace {
715 pub const DEFAULT: Self = Self(0);
717 pub const BT2020: Self = Self(1);
719}
720
721#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
723pub struct TransferFunction(pub u32);
724
725impl TransferFunction {
726 pub const DEFAULT: Self = Self(0);
728 pub const PQ: Self = Self(1);
730}