leenfetch_core/modules/linux/desktop/
resolution.rs1use std::{env, fs};
2
3#[cfg(feature = "x11")]
4mod x11 {
5 use libc::{c_char, c_int, c_ulong};
6 use std::ptr;
7
8 #[repr(C)]
9 struct XRRScreenConfiguration {
10 _private: [u8; 0],
11 }
12
13 #[repr(C)]
14 pub struct Display {
15 _private: [u8; 0],
16 }
17
18 type Window = c_ulong;
19
20 #[link(name = "X11")]
21 #[link(name = "Xrandr")]
22 unsafe extern "C" {
23 fn XOpenDisplay(display_name: *const c_char) -> *mut Display;
24 fn XCloseDisplay(display: *mut Display);
25 fn XDefaultScreen(display: *mut Display) -> c_int;
26 fn XDisplayWidth(display: *mut Display, screen_number: c_int) -> c_int;
27 fn XDisplayHeight(display: *mut Display, screen_number: c_int) -> c_int;
28
29 fn XRRGetScreenInfo(display: *mut Display, window: Window) -> *mut XRRScreenConfiguration;
30 fn XRRFreeScreenConfigInfo(config: *mut XRRScreenConfiguration);
31 fn XRRConfigCurrentRate(config: *mut XRRScreenConfiguration) -> i16;
32 fn XRootWindow(display: *mut Display, screen_number: c_int) -> Window;
33 }
34
35 pub fn try_x11(refresh_rate: bool) -> Option<String> {
36 unsafe {
37 let display = XOpenDisplay(ptr::null());
38 if display.is_null() {
39 return None;
40 }
41
42 let screen = XDefaultScreen(display);
43 let width = XDisplayWidth(display, screen);
44 let height = XDisplayHeight(display, screen);
45 let mut result = format!("{}x{}", width, height);
46
47 if refresh_rate {
48 let root = XRootWindow(display, screen);
49 let config = XRRGetScreenInfo(display, root);
50 if !config.is_null() {
51 let rate = XRRConfigCurrentRate(config);
52 result = format!("{} @ {}Hz", result, rate);
53 XRRFreeScreenConfigInfo(config);
54 }
55 }
56
57 XCloseDisplay(display);
58 Some(result)
59 }
60 }
61}
62
63#[cfg(not(feature = "x11"))]
64mod x11 {
65 pub fn try_x11(_refresh_rate: bool) -> Option<String> {
66 None
67 }
68}
69
70use x11::try_x11;
71
72pub fn get_resolution(refresh_rate: bool) -> Option<String> {
73 if env::var("DISPLAY").is_ok() {
75 if let Some(res) = try_x11(refresh_rate) {
76 return Some(res);
77 }
78 }
79
80 if let Some(res) = try_drm(refresh_rate) {
82 return Some(res);
83 }
84
85 if let Some(res) = try_fb() {
87 return Some(res);
88 }
89
90 if env::var("WAYLAND_DISPLAY").is_ok() {
92 return Some("Wayland: resolution unavailable (restricted by compositor)".to_string());
93 }
94
95 None
96}
97
98fn try_drm(refresh_rate: bool) -> Option<String> {
99 let entries = fs::read_dir("/sys/class/drm/").ok()?;
100
101 for entry in entries.flatten() {
102 let path = entry.path();
103 if path.file_name()?.to_str()?.contains("card") && path.join("status").exists() {
104 let status = fs::read_to_string(path.join("status")).ok()?;
105 if status.trim() != "connected" {
106 continue;
107 }
108
109 let mode_path = path.join("modes");
110 if mode_path.exists() {
111 let mode = fs::read_to_string(mode_path)
112 .ok()?
113 .lines()
114 .next()?
115 .to_string();
116 return Some(if refresh_rate {
117 format!("{} @ 60Hz", mode) } else {
119 mode
120 });
121 }
122 }
123 }
124
125 None
126}
127
128fn try_fb() -> Option<String> {
129 let contents = fs::read_to_string("/sys/class/graphics/fb0/virtual_size").ok()?;
130 let (w, h) = contents.trim().split_once(',')?;
131 Some(format!("{}x{}", w.trim(), h.trim()))
132}