1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! Display abstractions shared by `gpui` and its platform backends.
use crate::DEFAULT_WINDOW_SIZE;
use anyhow::Result;
use gpui_types::{Bounds, Pixels, point};
use std::fmt::{self, Debug};
use std::time::Duration;
use uuid::Uuid;
/// An opaque identifier for a hardware display
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct DisplayId(pub(crate) u64);
impl DisplayId {
/// Create a new `DisplayId` from a raw platform display identifier.
pub fn new(id: u64) -> Self {
Self(id)
}
}
impl From<u64> for DisplayId {
fn from(id: u64) -> Self {
Self(id)
}
}
impl From<DisplayId> for u64 {
fn from(id: DisplayId) -> Self {
id.0
}
}
impl Debug for DisplayId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "DisplayId({})", self.0)
}
}
/// A change to the connected displays, reported through
/// `App::observe_displays`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum DisplayEvent {
/// A display was connected.
Added(DisplayId),
/// A display was disconnected. Windows on it are moved to another
/// display by the platform.
Removed(DisplayId),
/// A connected display's properties changed.
Changed {
/// The display that changed.
id: DisplayId,
/// Which of its properties changed.
changes: DisplayChanges,
},
}
bitflags::bitflags! {
/// The properties of a display that a [`DisplayEvent::Changed`] reports.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct DisplayChanges: u8 {
/// [`PlatformDisplay::bounds`] changed.
const BOUNDS = 1 << 0;
/// [`PlatformDisplay::refresh_interval`] changed.
const REFRESH_INTERVAL = 1 << 1;
}
}
/// Converts a refresh rate in hertz to the time between refreshes, rejecting
/// the zero, negative, and non-finite rates platforms use to mean "unknown".
pub fn refresh_interval_from_hz(hertz: f64) -> Option<Duration> {
(hertz.is_finite() && hertz > 0.0).then(|| Duration::from_secs_f64(1.0 / hertz))
}
/// A handle to a platform's display, e.g. a monitor or laptop screen.
pub trait PlatformDisplay: Debug {
/// Get the ID for this display
fn id(&self) -> DisplayId;
/// Returns a stable identifier for this display that can be persisted and used
/// across system restarts.
fn uuid(&self) -> Result<Uuid>;
/// Get the bounds for this display
fn bounds(&self) -> Bounds<Pixels>;
/// The time between the display's refreshes. Variable refresh rate
/// displays report their maximum rate. `None` when the platform doesn't
/// report it.
///
/// May query the operating system; GPUI caches it per display, see
/// `Window::refresh_interval`.
fn refresh_interval(&self) -> Option<Duration>;
/// Get the visible bounds for this display, excluding taskbar/dock areas.
/// This is the usable area where windows can be placed without being obscured.
/// Defaults to the full display bounds if not overridden.
fn visible_bounds(&self) -> Bounds<Pixels> {
self.bounds()
}
/// Get the default bounds for this display to place a window
fn default_bounds(&self) -> Bounds<Pixels> {
let bounds = self.bounds();
let center = bounds.center();
let clipped_window_size = DEFAULT_WINDOW_SIZE.min(&bounds.size);
let offset = clipped_window_size / 2.0;
let origin = point(center.x - offset.width, center.y - offset.height);
Bounds::new(origin, clipped_window_size)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refresh_interval_from_hz() {
assert_eq!(
refresh_interval_from_hz(50.0),
Some(Duration::from_millis(20))
);
assert_eq!(
refresh_interval_from_hz(120.0),
Some(Duration::from_secs(1) / 120)
);
for unknown in [0.0, -60.0, f64::NAN, f64::INFINITY] {
assert_eq!(refresh_interval_from_hz(unknown), None);
}
}
}