Compare commits

...

3 Commits

Author SHA1 Message Date
Elf M. Sternberg e8bd037f61 Got the same functionality out of Rust, only prettier, and learned an important lesson about how much more Rust cares that the info you handled is, in fact, *fully* handled. 2022-04-18 17:26:10 -07:00
Elf M. Sternberg 0af01c5e0d Added showing the Output name along with the details (if any). 2022-04-18 16:01:41 -07:00
Elf M. Sternberg f60e935ffe This is a port of the C++ version of the XCB RandR reader.
I really, *really* like the way the Rust library is built and managed. It does a
really good job of emulating the XCB RandR macro found in KDE's Plasma and
libkscreen. The port was straightforward and my worries about memory management
were completely unfounded.
2022-04-15 19:52:53 -07:00
5 changed files with 147 additions and 1 deletions

View File

@ -40,5 +40,15 @@ And the following facts:
Work](https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/)... [TK]
- An output can have multiple CRTCs... but usually has only one.
Unresolved questions ...
- If the output encapsulates the _whole_ of screen (and the root window), when
we rotate the output who does coordinate remapping? I believe that's the
responsibility of the window manager. But if that's true, then what are the
implications for image viewers?
- If the output encapsulates only a subwindow of the whole, what is the
responsibility of the window manager when the new dimensions fit easily within
the screen as a whole?

View File

@ -33,9 +33,20 @@ void display_one_output(xcb_connection_t* connection, xcb_randr_get_output_info_
xcb_timestamp_t timestamp) {
xcb_randr_get_crtc_info_reply_t* crtc = xcb_randr_get_crtc_info_reply(
connection, xcb_randr_get_crtc_info(connection, output->crtc, timestamp), NULL);
// Note: This is part of the output structure natively; it's just not
// automagically exposed. (Opaque structures suck.) But it's both accessible
// and null-terminated, so it's relatively safe to use this way, and it does
// not require free() at the end.
auto name = xcb_randr_get_output_info_name(output);
if (name) {
std::cout << "DISPLAY: " << name << std::endl;
}
if (!crtc) {
return;
}
display_one_crtc(crtc);
free(crtc);
}

3
xcb_read_rs/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Cargo.lock
**/*.rs.bk
target

10
xcb_read_rs/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "xcb_read_rs"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libc = "0.2.102"
xcb = { version = "1.0.0-beta", features = ["randr"] }

112
xcb_read_rs/src/main.rs Normal file
View File

@ -0,0 +1,112 @@
use xcb::Xid;
extern crate libc;
extern crate xcb;
fn status_map(status: xcb::randr::SetConfig) -> &'static str {
match status {
xcb::randr::SetConfig::Success => "success",
xcb::randr::SetConfig::InvalidConfigTime => "invalid config time",
xcb::randr::SetConfig::InvalidTime => "invalid time",
xcb::randr::SetConfig::Failed => "failed",
}
}
fn rotation_map(rotation: xcb::randr::Rotation) -> &'static str {
match rotation {
xcb::randr::Rotation::ROTATE_0 => "normal",
xcb::randr::Rotation::ROTATE_90 => "portrait",
xcb::randr::Rotation::ROTATE_180 => "inverted",
xcb::randr::Rotation::ROTATE_270 => "portrait inverted",
_ => "unknown",
}
}
fn display_one_output(
conn: &xcb::Connection,
cookie: xcb::randr::GetOutputInfoCookie,
timestamp: xcb::x::Timestamp,
) {
let output = conn.wait_for_reply(cookie).unwrap();
if !(output.connection() == xcb::randr::Connection::Connected) {
return;
}
println!("Display: {}", std::str::from_utf8(output.name()).unwrap());
if output.crtc().resource_id() == 0 {
println!("(no monitor found)\n");
return;
}
let crtc = conn
.wait_for_reply(conn.send_request(&xcb::randr::GetCrtcInfo {
crtc: output.crtc(),
config_timestamp: timestamp,
}))
.unwrap();
println!(
"x: {}, y: {}, W×H: {}×{}, status: {}, rotation: {}\n",
crtc.x(),
crtc.y(),
crtc.width(),
crtc.height(),
status_map(crtc.status()),
rotation_map(crtc.rotation()),
)
}
fn display_outputs(
conn: &xcb::Connection,
screen: &xcb::randr::GetScreenResourcesReply,
timestamp: xcb::x::Timestamp,
) {
let output_cookies = screen.outputs().iter().map(|output| {
conn.send_request(&xcb::randr::GetOutputInfo {
output: *output,
config_timestamp: timestamp,
})
});
for cookie in output_cookies {
display_one_output(conn, cookie, timestamp)
}
}
fn get_screen_resources(
conn: &xcb::Connection,
root: &xcb::x::Window,
) -> xcb::randr::GetScreenResourcesReply {
conn.wait_for_reply(conn.send_request(&xcb::randr::GetScreenResources { window: *root }))
.unwrap()
}
fn display_xrandr_version(conn: &xcb::Connection) {
let randr_version = conn
.wait_for_reply(conn.send_request(&xcb::randr::QueryVersion {
major_version: xcb::randr::MAJOR_VERSION,
minor_version: xcb::randr::MINOR_VERSION,
}))
.unwrap();
println!(
"RandR Version {}.{}",
randr_version.major_version(),
randr_version.minor_version()
);
}
fn main() {
let (x_connection, screen_num) = xcb::Connection::connect(None).unwrap();
let setup = x_connection.get_setup();
let screen = setup.roots().nth(screen_num as usize).unwrap();
println!(
"{} x {}",
screen.width_in_pixels(),
screen.height_in_pixels()
);
display_xrandr_version(&x_connection);
let screen_resources = get_screen_resources(&x_connection, &screen.root());
let timestamp = screen_resources.config_timestamp();
display_outputs(&x_connection, &screen_resources, timestamp);
}