1use crate::DEFAULT_WINDOW_SIZE;
4use anyhow::Result;
5use gpui_types::{Bounds, Pixels, point};
6use std::fmt::{self, Debug};
7use std::time::Duration;
8use uuid::Uuid;
9
10#[derive(PartialEq, Eq, Hash, Copy, Clone)]
12pub struct DisplayId(pub(crate) u64);
13
14impl DisplayId {
15 pub fn new(id: u64) -> Self {
17 Self(id)
18 }
19}
20
21impl From<u64> for DisplayId {
22 fn from(id: u64) -> Self {
23 Self(id)
24 }
25}
26
27impl From<DisplayId> for u64 {
28 fn from(id: DisplayId) -> Self {
29 id.0
30 }
31}
32
33impl Debug for DisplayId {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "DisplayId({})", self.0)
36 }
37}
38
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42#[non_exhaustive]
43pub enum DisplayEvent {
44 Added(DisplayId),
46 Removed(DisplayId),
49 Changed {
51 id: DisplayId,
53 changes: DisplayChanges,
55 },
56}
57
58bitflags::bitflags! {
59 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61 pub struct DisplayChanges: u8 {
62 const BOUNDS = 1 << 0;
64 const REFRESH_INTERVAL = 1 << 1;
66 }
67}
68
69pub fn refresh_interval_from_hz(hertz: f64) -> Option<Duration> {
72 (hertz.is_finite() && hertz > 0.0).then(|| Duration::from_secs_f64(1.0 / hertz))
73}
74
75pub trait PlatformDisplay: Debug {
77 fn id(&self) -> DisplayId;
79
80 fn uuid(&self) -> Result<Uuid>;
83
84 fn bounds(&self) -> Bounds<Pixels>;
86
87 fn refresh_interval(&self) -> Option<Duration>;
94
95 fn visible_bounds(&self) -> Bounds<Pixels> {
99 self.bounds()
100 }
101
102 fn default_bounds(&self) -> Bounds<Pixels> {
104 let bounds = self.bounds();
105 let center = bounds.center();
106 let clipped_window_size = DEFAULT_WINDOW_SIZE.min(&bounds.size);
107
108 let offset = clipped_window_size / 2.0;
109 let origin = point(center.x - offset.width, center.y - offset.height);
110 Bounds::new(origin, clipped_window_size)
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117
118 #[test]
119 fn test_refresh_interval_from_hz() {
120 assert_eq!(
121 refresh_interval_from_hz(50.0),
122 Some(Duration::from_millis(20))
123 );
124 assert_eq!(
125 refresh_interval_from_hz(120.0),
126 Some(Duration::from_secs(1) / 120)
127 );
128 for unknown in [0.0, -60.0, f64::NAN, f64::INFINITY] {
129 assert_eq!(refresh_interval_from_hz(unknown), None);
130 }
131 }
132}