1use std::collections::HashMap;
2
3use gtk::{
4 gdk::{
5 self,
6 prelude::{DisplayExt, MonitorExt},
7 },
8 gio::prelude::ListModelExt,
9 glib::object::CastNone,
10};
11
12pub type Id = String;
14
15#[derive(Default, clap::Parser, serde::Serialize, serde::Deserialize, Debug, Clone)]
17pub struct MonitorMatch {
18 connector: Option<Id>,
19 manufacturer: Option<String>,
20 model: Option<String>,
21}
22
23impl From<gdk::Monitor> for MonitorMatch {
24 fn from(value: gdk::Monitor) -> Self {
25 Self {
26 connector: value.connector().map(|v| v.to_string()),
27 manufacturer: value.manufacturer().map(|v| v.to_string()),
28 model: value.model().map(|v| v.to_string()),
29 }
30 }
31}
32
33#[derive(Default, serde::Serialize, serde::Deserialize, Debug, Clone)]
34pub enum Monitor {
35 Dynamic,
37
38 Single(MonitorMatch),
40
41 Multi(Vec<MonitorMatch>),
43
44 #[default]
46 All,
47}
48
49pub fn all() -> Vec<gdk::Monitor> {
50 let monitors = gdk::Display::default().unwrap().monitors();
51
52 let mut output_monitors = vec![];
53
54 for i in 0..monitors.n_items() {
55 let Some(monitor): Option<gdk::Monitor> = monitors.item(i).and_downcast() else {
56 continue;
57 };
58 output_monitors.push(monitor);
59 }
60
61 output_monitors
62}
63
64impl MonitorMatch {
65 pub fn find_matches(&self) -> Vec<gdk::Monitor> {
66 let monitors = gdk::Display::default().unwrap().monitors();
67
68 let mut matched_monitors = vec![];
69
70 for i in 0..monitors.n_items() {
71 let Some(monitor): Option<gdk::Monitor> = monitors.item(i).and_downcast() else {
72 continue;
73 };
74
75 if let Some(connector) = &self.connector {
76 if monitor
77 .connector()
78 .map(|v| v.to_string())
79 .unwrap_or(format!(""))
80 != *connector
81 {
82 continue;
83 }
84 }
85
86 if let Some(manufacturer) = &self.manufacturer {
87 if monitor
88 .manufacturer()
89 .map(|v| v.to_string())
90 .unwrap_or(format!(""))
91 != *manufacturer
92 {
93 continue;
94 }
95 }
96
97 if let Some(model) = &self.model {
98 if monitor
99 .model()
100 .map(|v| v.to_string())
101 .unwrap_or(format!(""))
102 != *model
103 {
104 continue;
105 }
106 }
107
108 matched_monitors.push(monitor);
109 }
110
111 return matched_monitors;
112 }
113}
114
115pub fn monitors() -> Vec<gdk::Monitor> {
116 let monitors = gdk::Display::default().unwrap().monitors();
117 let mut output = vec![];
118
119 for i in 0..monitors.n_items() {
120 let Some(monitor): Option<gdk::Monitor> = monitors.item(i).and_downcast() else {
121 continue;
122 };
123 output.push(monitor);
124 }
125
126 output
127}
128
129pub fn monitors_to_string() -> String {
130 let output: Vec<HashMap<&str, String>> = monitors()
131 .iter()
132 .map(|monitor| {
133 HashMap::from([
134 (
135 "connector",
136 monitor
137 .connector()
138 .map(|v| v.to_string())
139 .unwrap_or_default(),
140 ),
141 (
142 "description",
143 monitor
144 .description()
145 .map(|v| v.to_string())
146 .unwrap_or_default(),
147 ),
148 (
149 "manufacturer",
150 monitor
151 .manufacturer()
152 .map(|v| v.to_string())
153 .unwrap_or_default(),
154 ),
155 (
156 "model",
157 monitor.model().map(|v| v.to_string()).unwrap_or_default(),
158 ),
159 ])
160 })
161 .collect();
162
163 serde_json::to_string_pretty(&output).unwrap()
164}
165
166pub fn get_monitor(index: u32) -> Option<gdk::Monitor> {
167 gdk::Display::default().and_then(|display| display.monitors().item(index).and_downcast())
168}