Skip to main content

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