jay_config/video.rs
1//! Tools for configuring graphics cards and monitors.
2
3use {
4 crate::{
5 _private::WireMode,
6 Direction, 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/// The mode of a connector.
19///
20/// Currently a mode consists of three properties:
21///
22/// - width in pixels
23/// - height in pixels
24/// - refresh rate in mhz.
25#[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 /// Returns the width of the mode.
34 pub fn width(&self) -> i32 {
35 self.width
36 }
37
38 /// Returns the height of the mode.
39 pub fn height(&self) -> i32 {
40 self.height
41 }
42
43 /// Returns the refresh rate of the mode in mhz.
44 ///
45 /// For a 60hz monitor, this function would return 60_000.
46 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/// A connector that is potentially connected to an output device.
60///
61/// A connector is the part that sticks out of your graphics card. A graphics card usually
62/// has many connectors but one few of them are actually connected to a monitor.
63#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
64pub struct Connector(pub u64);
65
66impl Connector {
67 /// Returns whether this connector existed at the time `get_connector` was called.
68 ///
69 /// This only implies existence at the time `get_connector` was called. Even if this
70 /// function returns true, the connector might since have disappeared.
71 pub fn exists(self) -> bool {
72 self.0 != 0
73 }
74
75 /// Returns whether the connector is connected to an output device.
76 pub fn connected(self) -> bool {
77 if !self.exists() {
78 return false;
79 }
80 get!(false).connector_connected(self)
81 }
82
83 /// Returns whether this connector is used as an output by the compositor.
84 pub fn compositor_output(self) -> bool {
85 get!(false).connector_compositor_output(self)
86 }
87
88 /// Returns the scale of the currently connected monitor.
89 pub fn scale(self) -> f64 {
90 if !self.exists() {
91 return 1.0;
92 }
93 get!(1.0).connector_get_scale(self)
94 }
95
96 /// Sets the scale to use for the currently connected monitor.
97 pub fn set_scale(self, scale: f64) {
98 if !self.exists() {
99 return;
100 }
101 log::info!("setting scale to {}", scale);
102 get!().connector_set_scale(self, scale);
103 }
104
105 /// Returns the connector type.
106 pub fn ty(self) -> ConnectorType {
107 if !self.exists() {
108 return CON_UNKNOWN;
109 }
110 get!(CON_UNKNOWN).connector_type(self)
111 }
112
113 /// Returns the current mode of the connector.
114 pub fn mode(self) -> Mode {
115 if !self.exists() {
116 return Mode::zeroed();
117 }
118 get!(Mode::zeroed()).connector_mode(self)
119 }
120
121 /// Tries to set the mode of the connector.
122 ///
123 /// If the refresh rate is not specified, tries to use the first mode with the given
124 /// width and height.
125 ///
126 /// The default mode is the first mode advertised by the connector. This is usually
127 /// the native mode.
128 pub fn set_mode(self, width: i32, height: i32, refresh_millihz: Option<u32>) {
129 if !self.exists() {
130 log::warn!("set_mode called on a connector that does not exist");
131 return;
132 }
133 let refresh_millihz = match refresh_millihz {
134 Some(r) => r,
135 _ => match self
136 .modes()
137 .iter()
138 .find(|m| m.width == width && m.height == height)
139 {
140 Some(m) => m.refresh_millihz,
141 _ => {
142 log::warn!("Could not find any mode with width {width} and height {height}");
143 return;
144 }
145 },
146 };
147 get!().connector_set_mode(
148 self,
149 WireMode {
150 width,
151 height,
152 refresh_millihz,
153 },
154 )
155 }
156
157 /// Returns the available modes of the connector.
158 pub fn modes(self) -> Vec<Mode> {
159 if !self.exists() {
160 return Vec::new();
161 }
162 get!(Vec::new()).connector_modes(self)
163 }
164
165 /// Returns whether this connector supports arbitrary modes.
166 pub fn supports_arbitrary_modes(self) -> bool {
167 if !self.exists() {
168 return false;
169 }
170 get!(false).connector_supports_arbitrary_modes(self)
171 }
172
173 /// Returns the logical width of the connector.
174 ///
175 /// The returned value will be different from `mode().width()` if the scale is not 1.
176 pub fn width(self) -> i32 {
177 get!().connector_size(self).0
178 }
179
180 /// Returns the logical height of the connector.
181 ///
182 /// The returned value will be different from `mode().height()` if the scale is not 1.
183 pub fn height(self) -> i32 {
184 get!().connector_size(self).1
185 }
186
187 /// Returns the refresh rate in mhz of the current mode of the connector.
188 ///
189 /// This is a shortcut for `mode().refresh_rate()`.
190 pub fn refresh_rate(self) -> u32 {
191 self.mode().refresh_millihz
192 }
193
194 /// Retrieves the position of the output in the global compositor space.
195 pub fn position(self) -> (i32, i32) {
196 if !self.connected() {
197 return (0, 0);
198 }
199 get!().connector_get_position(self)
200 }
201
202 /// Sets the position of the connector in the global compositor space.
203 ///
204 /// `x` and `y` must be non-negative and must not exceed a currently unspecified limit.
205 /// Any reasonable values for `x` and `y` should work.
206 ///
207 /// This function allows the connector to overlap with other connectors, however, such
208 /// configurations are not supported and might result in unexpected behavior.
209 pub fn set_position(self, x: i32, y: i32) {
210 if !self.exists() {
211 log::warn!("set_position called on a connector that does not exist");
212 return;
213 }
214 get!().connector_set_position(self, x, y);
215 }
216
217 /// Enables or disables the connector.
218 ///
219 /// By default, all connectors are enabled.
220 pub fn set_enabled(self, enabled: bool) {
221 if !self.exists() {
222 log::warn!("set_enabled called on a connector that does not exist");
223 return;
224 }
225 get!().connector_set_enabled(self, enabled);
226 }
227
228 /// Sets the transformation to apply to the content of this connector.
229 pub fn set_transform(self, transform: Transform) {
230 if !self.exists() {
231 log::warn!("set_transform called on a connector that does not exist");
232 return;
233 }
234 get!().connector_set_transform(self, transform);
235 }
236
237 pub fn name(self) -> String {
238 if !self.exists() {
239 return String::new();
240 }
241 get!(String::new()).connector_get_name(self)
242 }
243
244 pub fn model(self) -> String {
245 if !self.exists() {
246 return String::new();
247 }
248 get!(String::new()).connector_get_model(self)
249 }
250
251 pub fn manufacturer(self) -> String {
252 if !self.exists() {
253 return String::new();
254 }
255 get!(String::new()).connector_get_manufacturer(self)
256 }
257
258 pub fn serial_number(self) -> String {
259 if !self.exists() {
260 return String::new();
261 }
262 get!(String::new()).connector_get_serial_number(self)
263 }
264
265 /// Sets the VRR mode.
266 pub fn set_vrr_mode(self, mode: VrrMode) {
267 get!().set_vrr_mode(Some(self), mode)
268 }
269
270 /// Sets the VRR cursor refresh rate.
271 ///
272 /// Limits the rate at which cursors are updated on screen when VRR is active.
273 ///
274 /// Setting this to infinity disables the limiter.
275 pub fn set_vrr_cursor_hz(self, hz: f64) {
276 get!().set_vrr_cursor_hz(Some(self), hz)
277 }
278
279 /// Sets the tearing mode.
280 pub fn set_tearing_mode(self, mode: TearingMode) {
281 get!().set_tearing_mode(Some(self), mode)
282 }
283
284 /// Sets the format to use for framebuffers.
285 pub fn set_format(self, format: Format) {
286 get!().connector_set_format(self, format);
287 }
288
289 /// Sets the color space and EOTF of the connector.
290 ///
291 /// By default, the default values are used which usually means sRGB color space with
292 /// gamma22 EOTF.
293 ///
294 /// If the output supports it, HDR10 can be enabled by setting the color space to
295 /// BT.2020 and the EOTF to PQ.
296 ///
297 /// Note that some displays might ignore incompatible settings.
298 pub fn set_colors(self, color_space: ColorSpace, eotf: Eotf) {
299 get!().connector_set_colors(self, color_space, eotf);
300 }
301
302 /// Sets the space in which blending is performed for this output.
303 ///
304 /// The default is [`BlendSpace::SRGB`]
305 pub fn set_blend_space(self, blend_space: BlendSpace) {
306 get!().connector_set_blend_space(self, blend_space);
307 }
308
309 /// Sets the brightness of the output.
310 ///
311 /// By default or when `brightness` is `None`, the brightness depends on the
312 /// EOTF:
313 ///
314 /// - [`Eotf::DEFAULT`]: The maximum brightness of the output.
315 /// - [`Eotf::PQ`]: 203 cd/m^2.
316 ///
317 /// This should only be used with the PQ transfer function. If the default transfer
318 /// function is used, you should instead calibrate the hardware directly.
319 ///
320 /// When used with the default transfer function, the default brightness is anchored
321 /// at 80 cd/m^2. That is, setting this to 40 cd/m^2 makes everything appear half as
322 /// bright as normal and creates 50% HDR headroom.
323 ///
324 /// This has no effect unless the vulkan renderer is used.
325 pub fn set_brightness(self, brightness: Option<f64>) {
326 get!().connector_set_brightness(self, brightness);
327 }
328
329 /// Get the currently visible/active workspace.
330 ///
331 /// If this connector is not connected, or is there no active workspace, returns a
332 /// workspace whose `exists()` returns false.
333 pub fn active_workspace(self) -> Workspace {
334 get!(Workspace(0)).get_connector_active_workspace(self)
335 }
336
337 /// Get all workspaces on this connector.
338 ///
339 /// If this connector is not connected, returns an empty list.
340 pub fn workspaces(self) -> Vec<Workspace> {
341 get!().get_connector_workspaces(self)
342 }
343
344 /// Find the closest connector in the given direction.
345 ///
346 /// Uses center-to-center distance calculation and prefers outputs better aligned
347 /// with the movement axis.
348 ///
349 /// If no connector exists in the given direction, returns a connector whose
350 /// `exists()` returns false.
351 pub fn connector_in_direction(self, direction: Direction) -> Connector {
352 get!(Connector(0)).get_connector_in_direction(self, direction)
353 }
354
355 /// Configures whether the display primaries are used.
356 ///
357 /// By default, Jay pretends that the display uses sRGB primaries. This is also how
358 /// most other systems behave. In reality, most displays use a much larger gamut. For
359 /// example, they advertise that they support 95% of the DCI-P3 gamut. If the display
360 /// is interpreting colors in their native gamut, then colors will appear more
361 /// saturated than their specification.
362 ///
363 /// If this is set to `true`, Jay assumes that the display uses the primaries
364 /// advertised in its EDID. This might produce more accurate colors while also
365 /// allowing color-managed applications to use the full gamut of the display.
366 ///
367 /// This setting has no effect when the display is explicitly operating in a wide
368 /// color space.
369 ///
370 /// The default is `false`.
371 pub fn set_use_native_gamut(self, use_native_gamut: bool) {
372 get!().connector_set_use_native_gamut(self, use_native_gamut);
373 }
374}
375
376/// Returns all available DRM devices.
377pub fn drm_devices() -> Vec<DrmDevice> {
378 get!().drm_devices()
379}
380
381/// Sets the callback to be called when a new DRM device appears.
382pub fn on_new_drm_device<F: FnMut(DrmDevice) + 'static>(f: F) {
383 get!().on_new_drm_device(f)
384}
385
386/// Sets the callback to be called when a DRM device is removed.
387pub fn on_drm_device_removed<F: FnMut(DrmDevice) + 'static>(f: F) {
388 get!().on_del_drm_device(f)
389}
390
391/// Sets the callback to be called when a new connector appears.
392pub fn on_new_connector<F: FnMut(Connector) + 'static>(f: F) {
393 get!().on_new_connector(f)
394}
395
396/// Sets the callback to be called when a connector becomes connected to an output device.
397pub fn on_connector_connected<F: FnMut(Connector) + 'static>(f: F) {
398 get!().on_connector_connected(f)
399}
400
401/// Sets the callback to be called when a connector is disconnected from an output device.
402pub fn on_connector_disconnected<F: FnMut(Connector) + 'static>(f: F) {
403 get!().on_connector_disconnected(f)
404}
405
406/// Sets the callback to be called when the graphics of the compositor have been initialized.
407///
408/// This callback is only invoked once during the lifetime of the compositor. This is a good place
409/// to auto start graphical applications.
410pub fn on_graphics_initialized<F: FnOnce() + 'static>(f: F) {
411 get!().on_graphics_initialized(f)
412}
413
414pub fn connectors() -> Vec<Connector> {
415 get!().connectors(None)
416}
417
418/// Returns the connector with the given id.
419///
420/// The linux kernel identifies connectors by a (type, idx) tuple, e.g., `DP-0`.
421/// If the connector does not exist at the time this function is called, a sentinel value is
422/// returned. This can be checked by calling `exists()` on the returned connector.
423///
424/// The `id` argument can either be an explicit tuple, e.g. `(CON_DISPLAY_PORT, 0)`, or a string
425/// that can be parsed to such a tuple, e.g. `"DP-0"`.
426///
427/// The following string prefixes exist:
428///
429/// - `DP`
430/// - `eDP`
431/// - `HDMI-A`
432/// - `HDMI-B`
433/// - `EmbeddedWindow` - this is an implementation detail of the compositor and used if it
434/// runs as an embedded application.
435/// - `VGA`
436/// - `DVI-I`
437/// - `DVI-D`
438/// - `DVI-A`
439/// - `Composite`
440/// - `SVIDEO`
441/// - `LVDS`
442/// - `Component`
443/// - `DIN`
444/// - `TV`
445/// - `Virtual`
446/// - `DSI`
447/// - `DPI`
448/// - `Writeback`
449/// - `SPI`
450/// - `USB`
451pub fn get_connector(id: impl ToConnectorId) -> Connector {
452 let (ty, idx) = match id.to_connector_id() {
453 Ok(id) => id,
454 Err(e) => {
455 log::error!("{}", e);
456 return Connector(0);
457 }
458 };
459 get!(Connector(0)).get_connector(ty, idx)
460}
461
462/// Returns the connector with the given name.
463///
464/// Unlike [`get_connector`], this function can also be used for connectors whose names
465/// don't follow the `<type>-<id>` pattern.
466pub fn get_connector_by_name(name: &str) -> Connector {
467 get!(Connector(0)).get_connector_by_name(name)
468}
469
470/// A type that can be converted to a `(ConnectorType, idx)` tuple.
471pub trait ToConnectorId {
472 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String>;
473}
474
475impl ToConnectorId for (ConnectorType, u32) {
476 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
477 Ok(*self)
478 }
479}
480
481impl ToConnectorId for &'_ str {
482 fn to_connector_id(&self) -> Result<(ConnectorType, u32), String> {
483 let pairs = [
484 ("DP-", CON_DISPLAY_PORT),
485 ("eDP-", CON_EDP),
486 ("HDMI-A-", CON_HDMIA),
487 ("HDMI-B-", CON_HDMIB),
488 ("EmbeddedWindow-", CON_EMBEDDED_WINDOW),
489 ("VGA-", CON_VGA),
490 ("DVI-I-", CON_DVII),
491 ("DVI-D-", CON_DVID),
492 ("DVI-A-", CON_DVIA),
493 ("Composite-", CON_COMPOSITE),
494 ("SVIDEO-", CON_SVIDEO),
495 ("LVDS-", CON_LVDS),
496 ("Component-", CON_COMPONENT),
497 ("DIN-", CON_9PIN_DIN),
498 ("TV-", CON_TV),
499 ("Virtual-", CON_VIRTUAL),
500 ("DSI-", CON_DSI),
501 ("DPI-", CON_DPI),
502 ("Writeback-", CON_WRITEBACK),
503 ("SPI-", CON_SPI),
504 ("USB-", CON_USB),
505 ];
506 for (prefix, ty) in pairs {
507 if let Some(suffix) = self.strip_prefix(prefix)
508 && let Ok(idx) = u32::from_str(suffix)
509 {
510 return Ok((ty, idx));
511 }
512 }
513 Err(format!("`{}` is not a valid connector identifier", self))
514 }
515}
516
517/// Module containing all known connector types.
518pub mod connector_type {
519 use serde::{Deserialize, Serialize};
520
521 /// The type of a connector.
522 #[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
523 pub struct ConnectorType(pub u32);
524
525 pub const CON_UNKNOWN: ConnectorType = ConnectorType(0);
526 pub const CON_VGA: ConnectorType = ConnectorType(1);
527 pub const CON_DVII: ConnectorType = ConnectorType(2);
528 pub const CON_DVID: ConnectorType = ConnectorType(3);
529 pub const CON_DVIA: ConnectorType = ConnectorType(4);
530 pub const CON_COMPOSITE: ConnectorType = ConnectorType(5);
531 pub const CON_SVIDEO: ConnectorType = ConnectorType(6);
532 pub const CON_LVDS: ConnectorType = ConnectorType(7);
533 pub const CON_COMPONENT: ConnectorType = ConnectorType(8);
534 pub const CON_9PIN_DIN: ConnectorType = ConnectorType(9);
535 pub const CON_DISPLAY_PORT: ConnectorType = ConnectorType(10);
536 pub const CON_HDMIA: ConnectorType = ConnectorType(11);
537 pub const CON_HDMIB: ConnectorType = ConnectorType(12);
538 pub const CON_TV: ConnectorType = ConnectorType(13);
539 pub const CON_EDP: ConnectorType = ConnectorType(14);
540 pub const CON_VIRTUAL: ConnectorType = ConnectorType(15);
541 pub const CON_DSI: ConnectorType = ConnectorType(16);
542 pub const CON_DPI: ConnectorType = ConnectorType(17);
543 pub const CON_WRITEBACK: ConnectorType = ConnectorType(18);
544 pub const CON_SPI: ConnectorType = ConnectorType(19);
545 pub const CON_USB: ConnectorType = ConnectorType(20);
546 pub const CON_EMBEDDED_WINDOW: ConnectorType = ConnectorType(u32::MAX);
547 pub const CON_VIRTUAL_OUTPUT: ConnectorType = ConnectorType(u32::MAX - 1);
548}
549
550/// A *Direct Rendering Manager* (DRM) device.
551///
552/// It's easiest to think of a DRM device as a graphics card.
553/// There are also DRM devices that are emulated in software but you are unlikely to encounter
554/// those accidentally.
555#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
556pub struct DrmDevice(pub u64);
557
558impl DrmDevice {
559 /// Returns the connectors of this device.
560 pub fn connectors(self) -> Vec<Connector> {
561 get!().connectors(Some(self))
562 }
563
564 /// Returns the devnode of this device.
565 ///
566 /// E.g. `/dev/dri/card0`.
567 pub fn devnode(self) -> String {
568 get!().drm_device_devnode(self)
569 }
570
571 /// Returns the syspath of this device.
572 ///
573 /// E.g. `/sys/devices/pci0000:00/0000:00:03.1/0000:07:00.0`.
574 pub fn syspath(self) -> String {
575 get!().drm_device_syspath(self)
576 }
577
578 /// Returns the vendor of this device.
579 ///
580 /// E.g. `Advanced Micro Devices, Inc. [AMD/ATI]`.
581 pub fn vendor(self) -> String {
582 get!().drm_device_vendor(self)
583 }
584
585 /// Returns the model of this device.
586 ///
587 /// E.g. `Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570 Armor 8G OC)`.
588 pub fn model(self) -> String {
589 get!().drm_device_model(self)
590 }
591
592 /// Returns the PIC ID of this device.
593 ///
594 /// E.g. `1002:67DF`.
595 pub fn pci_id(self) -> PciId {
596 get!().drm_device_pci_id(self)
597 }
598
599 /// Makes this device the render device.
600 pub fn make_render_device(self) {
601 get!().make_render_device(self);
602 }
603
604 /// Sets the preferred graphics API for this device.
605 ///
606 /// If the API cannot be used, the compositor will try other APIs.
607 pub fn set_gfx_api(self, gfx_api: GfxApi) {
608 get!().set_gfx_api(Some(self), gfx_api);
609 }
610
611 /// Enables or disables direct scanout of client surfaces for this device.
612 pub fn set_direct_scanout_enabled(self, enabled: bool) {
613 get!().set_direct_scanout_enabled(Some(self), enabled);
614 }
615
616 /// Sets the flip margin of this device.
617 ///
618 /// This is duration between the compositor initiating a page flip and the output's
619 /// vblank event. This determines the minimum input latency. The default is 1.5 ms.
620 ///
621 /// Note that if the margin is too small, the compositor will dynamically increase it.
622 pub fn set_flip_margin(self, margin: Duration) {
623 get!().set_flip_margin(self, margin);
624 }
625}
626
627/// A graphics API.
628#[non_exhaustive]
629#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq)]
630pub enum GfxApi {
631 OpenGl,
632 Vulkan,
633}
634
635/// Sets the default graphics API.
636///
637/// If the API cannot be used, the compositor will try other APIs.
638///
639/// This setting can be overwritten per-device with [DrmDevice::set_gfx_api].
640///
641/// This call has no effect on devices that have already been initialized.
642pub fn set_gfx_api(gfx_api: GfxApi) {
643 get!().set_gfx_api(None, gfx_api);
644}
645
646/// Enables or disables direct scanout of client surfaces.
647///
648/// The default is `true`.
649///
650/// This setting can be overwritten per-device with [DrmDevice::set_direct_scanout_enabled].
651pub fn set_direct_scanout_enabled(enabled: bool) {
652 get!().set_direct_scanout_enabled(None, enabled);
653}
654
655/// A transformation.
656#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
657pub enum Transform {
658 /// No transformation.
659 #[default]
660 None,
661 /// Rotate 90 degrees counter-clockwise.
662 Rotate90,
663 /// Rotate 180 degrees counter-clockwise.
664 Rotate180,
665 /// Rotate 270 degrees counter-clockwise.
666 Rotate270,
667 /// Flip around the vertical axis.
668 Flip,
669 /// Flip around the vertical axis, then rotate 90 degrees counter-clockwise.
670 FlipRotate90,
671 /// Flip around the vertical axis, then rotate 180 degrees counter-clockwise.
672 FlipRotate180,
673 /// Flip around the vertical axis, then rotate 270 degrees counter-clockwise.
674 FlipRotate270,
675}
676
677/// The VRR mode of a connector.
678#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
679pub struct VrrMode(pub u32);
680
681impl VrrMode {
682 /// VRR is never enabled.
683 pub const NEVER: Self = Self(0);
684 /// VRR is always enabled.
685 pub const ALWAYS: Self = Self(1);
686 /// VRR is enabled when one or more applications are displayed fullscreen.
687 pub const VARIANT_1: Self = Self(2);
688 /// VRR is enabled when a single application is displayed fullscreen.
689 pub const VARIANT_2: Self = Self(3);
690 /// VRR is enabled when a single game or video is displayed fullscreen.
691 pub const VARIANT_3: Self = Self(4);
692}
693
694/// Sets the default VRR mode.
695///
696/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_mode].
697pub fn set_vrr_mode(mode: VrrMode) {
698 get!().set_vrr_mode(None, mode)
699}
700
701/// Sets the VRR cursor refresh rate.
702///
703/// Limits the rate at which cursors are updated on screen when VRR is active.
704///
705/// Setting this to infinity disables the limiter.
706///
707/// This setting can be overwritten on a per-connector basis with [Connector::set_vrr_cursor_hz].
708pub fn set_vrr_cursor_hz(hz: f64) {
709 get!().set_vrr_cursor_hz(None, hz)
710}
711
712/// The tearing mode of a connector.
713#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash, Default)]
714pub struct TearingMode(pub u32);
715
716impl TearingMode {
717 /// Tearing is never enabled.
718 pub const NEVER: Self = Self(0);
719 /// Tearing is always enabled.
720 pub const ALWAYS: Self = Self(1);
721 /// Tearing is enabled when one or more applications are displayed fullscreen.
722 pub const VARIANT_1: Self = Self(2);
723 /// Tearing is enabled when a single application is displayed fullscreen.
724 pub const VARIANT_2: Self = Self(3);
725 /// Tearing is enabled when a single application is displayed fullscreen and the
726 /// application has requested tearing.
727 ///
728 /// This is the default.
729 pub const VARIANT_3: Self = Self(4);
730}
731
732/// Sets the default tearing mode.
733///
734/// This setting can be overwritten on a per-connector basis with [Connector::set_tearing_mode].
735pub fn set_tearing_mode(mode: TearingMode) {
736 get!().set_tearing_mode(None, mode)
737}
738
739/// Creates a virtual output with the given name.
740///
741/// This is a no-op if a virtual output with that name already exists.
742///
743/// The created connector can be accessed with [`get_connector_by_name("VO-{name}")`].
744///
745/// A newly created connector is initially disabled. When a connector is destroyed and
746/// later recreated, its previous state is restored.
747pub fn create_virtual_output(name: &str) {
748 get!().create_virtual_output(name);
749}
750
751/// Removes the virtual output with the given name.
752///
753/// This is a no-op if a virtual output with that name does not exist.
754pub fn remove_virtual_output(name: &str) {
755 get!().remove_virtual_output(name);
756}
757
758/// A graphics format.
759#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
760pub struct Format(pub u32);
761
762impl Format {
763 pub const ARGB8888: Self = Self(0);
764 pub const XRGB8888: Self = Self(1);
765 pub const ABGR8888: Self = Self(2);
766 pub const XBGR8888: Self = Self(3);
767 pub const R8: Self = Self(4);
768 pub const GR88: Self = Self(5);
769 pub const RGB888: Self = Self(6);
770 pub const BGR888: Self = Self(7);
771 pub const RGBA4444: Self = Self(8);
772 pub const RGBX4444: Self = Self(9);
773 pub const BGRA4444: Self = Self(10);
774 pub const BGRX4444: Self = Self(11);
775 pub const RGB565: Self = Self(12);
776 pub const BGR565: Self = Self(13);
777 pub const RGBA5551: Self = Self(14);
778 pub const RGBX5551: Self = Self(15);
779 pub const BGRA5551: Self = Self(16);
780 pub const BGRX5551: Self = Self(17);
781 pub const ARGB1555: Self = Self(18);
782 pub const XRGB1555: Self = Self(19);
783 pub const ARGB2101010: Self = Self(20);
784 pub const XRGB2101010: Self = Self(21);
785 pub const ABGR2101010: Self = Self(22);
786 pub const XBGR2101010: Self = Self(23);
787 pub const ABGR16161616: Self = Self(24);
788 pub const XBGR16161616: Self = Self(25);
789 pub const ABGR16161616F: Self = Self(26);
790 pub const XBGR16161616F: Self = Self(27);
791 pub const BGR161616: Self = Self(28);
792 pub const R16F: Self = Self(29);
793 pub const GR1616F: Self = Self(30);
794 pub const BGR161616F: Self = Self(31);
795 pub const R32F: Self = Self(32);
796 pub const GR3232F: Self = Self(33);
797 pub const BGR323232F: Self = Self(34);
798 pub const ABGR32323232F: Self = Self(35);
799}
800
801/// A color space.
802#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
803pub struct ColorSpace(pub u32);
804
805impl ColorSpace {
806 /// The default color space (usually sRGB).
807 pub const DEFAULT: Self = Self(0);
808 /// The BT.2020 color space.
809 pub const BT2020: Self = Self(1);
810}
811
812/// An electro-optical transfer function (EOTF).
813#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
814pub struct Eotf(pub u32);
815
816#[deprecated = "use the Eotf type instead"]
817pub type TransferFunction = Eotf;
818
819impl Eotf {
820 /// The default EOTF (usually gamma22).
821 pub const DEFAULT: Self = Self(0);
822 /// The PQ EOTF.
823 pub const PQ: Self = Self(1);
824}
825
826/// A space in which color blending is performed.
827#[derive(Serialize, Deserialize, Copy, Clone, Debug, Eq, PartialEq, Hash)]
828pub struct BlendSpace(pub u32);
829
830impl BlendSpace {
831 /// The sRGB blend space with sRGB primaries and gamma22 transfer function. This is
832 /// the classic desktop blend space.
833 pub const SRGB: Self = Self(0);
834 /// The linear blend space performs blending in linear space, which is more physically
835 /// correct but leads to much lighter output when blending light and dark colors.
836 pub const LINEAR: Self = Self(1);
837}