Compare commits
	
		
			3 Commits
		
	
	
		
			f821d87ba3
			...
			master
		
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | e8bd037f61 | |
|  | 0af01c5e0d | |
|  | f60e935ffe | 
|  | @ -40,5 +40,15 @@ And the following facts: | ||||||
|   Work](https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/)... [TK] |   Work](https://www.x.org/wiki/Development/Documentation/HowVideoCardsWork/)... [TK] | ||||||
| - An output can have multiple CRTCs... but usually has only one. | - 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? | ||||||
|  |    | ||||||
|  |    | ||||||
|  |  | ||||||
|  | @ -33,9 +33,20 @@ void display_one_output(xcb_connection_t* connection, xcb_randr_get_output_info_ | ||||||
|                         xcb_timestamp_t timestamp) { |                         xcb_timestamp_t timestamp) { | ||||||
|     xcb_randr_get_crtc_info_reply_t* crtc = xcb_randr_get_crtc_info_reply( |     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); |         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) { |     if (!crtc) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     display_one_crtc(crtc); |     display_one_crtc(crtc); | ||||||
|     free(crtc); |     free(crtc); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | Cargo.lock | ||||||
|  | **/*.rs.bk | ||||||
|  | target | ||||||
|  | @ -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"] } | ||||||
|  | @ -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); | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue