Skip to main content

monitor_info/
monitor_info.rs

1//! Displays information about available monitors (displays).
2
3use bevy::{
4    camera::RenderTarget,
5    prelude::*,
6    window::{ExitCondition, Monitor, OnMonitor, WindowMode, WindowRef},
7};
8
9fn main() {
10    App::new()
11        .add_plugins(DefaultPlugins.set(WindowPlugin {
12            primary_window: None,
13            exit_condition: ExitCondition::DontExit,
14            ..default()
15        }))
16        .add_systems(Update, (update, close_on_esc))
17        .run();
18}
19
20fn update(
21    mut commands: Commands,
22    monitors_added: Query<(Entity, &Monitor), Added<Monitor>>,
23    mut monitors_removed: RemovedComponents<Monitor>,
24    windows: Query<(Entity, &OnMonitor)>,
25) {
26    for (entity, monitor) in monitors_added.iter() {
27        // Spawn a new window on each monitor
28        let name = monitor.name.clone().unwrap_or_else(|| "<no name>".into());
29        let size = format!("{}x{}px", monitor.physical_height, monitor.physical_width);
30        let hz = monitor
31            .refresh_rate_millihertz
32            .map(|x| format!("{}Hz", x as f32 / 1000.0))
33            .unwrap_or_else(|| "<unknown>".into());
34        let position = format!(
35            "x={} y={}",
36            monitor.physical_position.x, monitor.physical_position.y
37        );
38        let scale = format!("{:.2}", monitor.scale_factor);
39
40        let window = commands
41            .spawn((Window {
42                title: name.clone(),
43                mode: WindowMode::Fullscreen(
44                    MonitorSelection::Entity(entity),
45                    VideoModeSelection::Current,
46                ),
47                position: WindowPosition::Centered(MonitorSelection::Entity(entity)),
48                ..default()
49            },))
50            .id();
51
52        let camera = commands
53            .spawn((Camera2d, RenderTarget::Window(WindowRef::Entity(window))))
54            .id();
55
56        let info_text = format!(
57            "Monitor: {name}\nSize: {size}\nRefresh rate: {hz}\nPosition: {position}\nScale: {scale}\n\n",
58        );
59        commands.spawn((
60            Text(info_text),
61            Node {
62                position_type: PositionType::Relative,
63                height: percent(100),
64                width: percent(100),
65                ..default()
66            },
67            UiTargetCamera(camera),
68        ));
69    }
70
71    // Remove windows for removed monitors
72    for monitor_entity in monitors_removed.read() {
73        for (window_entity, on_monitor) in windows.iter() {
74            if on_monitor.0 == monitor_entity {
75                commands.entity(window_entity).despawn();
76            }
77        }
78    }
79}
80
81fn close_on_esc(
82    mut commands: Commands,
83    focused_windows: Query<(Entity, &Window)>,
84    input: Res<ButtonInput<KeyCode>>,
85) {
86    for (window, focus) in focused_windows.iter() {
87        if !focus.focused {
88            continue;
89        }
90
91        if input.just_pressed(KeyCode::Escape) {
92            commands.entity(window).despawn();
93        }
94    }
95}