Created
July 22, 2017 18:53
-
-
Save saethlin/234e3f9a3a1f56a0f034d9788dff9976 to your computer and use it in GitHub Desktop.
Rust-XCB demo
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate xcb; // Make sure you add xcb to your Caro.toml dependencies | |
fn main() { | |
// First thing you have to do is get a connection. You can pass an argument | |
// but if you just leave it as None you'll connect to the display device you're currently on | |
let (connection, screen_num) = xcb::Connection::connect(None).unwrap(); | |
let setup = connection.get_setup(); | |
let screen = setup.roots().nth(screen_num as usize).unwrap(); | |
// Now we have a connection to the X server (remember X does things sort of backwards, | |
// the client is the far away machine, the server is where you are). | |
// To make anything of it, we need to create an ID. This is like allocating memory for a variable. | |
let window = connection.generate_id(); | |
// And with an ID created, we need to do a bit more voodoo before we can make a window: | |
// This is an array that identifies a few properties of the window. | |
// I think the first one is some drawing color defaults, and the second element is | |
// an event mask that determines which events the client will send to the server. | |
// Sometimes this is called registering for events | |
let values = [ | |
(xcb::CW_BACK_PIXEL, screen.white_pixel()), | |
( | |
xcb::CW_EVENT_MASK, | |
xcb::EVENT_MASK_EXPOSURE | xcb::EVENT_MASK_KEY_PRESS, | |
), | |
]; | |
// Now to build a window on that connection: | |
xcb::create_window( | |
&connection, | |
xcb::COPY_FROM_PARENT as u8, | |
window, | |
screen.root(), | |
0, | |
0, // window origin x an y, I can't figure out if this actually does anything | |
800, // window width | |
500, // window height | |
10, // border size, I'm not convinced this does anything either | |
xcb::WINDOW_CLASS_INPUT_OUTPUT as u16, | |
screen.root_visual(), | |
&values, | |
); | |
// Note that this call doesn't return _or_ mutate anything. | |
// Welcome to X, where nothing makes sense and everyone authenticates with `MIT-MAGIC-COOKIE-1`. | |
// Now we need to map the window to the screen, then flush the connection to be sure something happens. | |
xcb::map_window(&connection, window); | |
connection.flush(); | |
// At this point the window just goes out of scope, so we need to actually do something to keep it alive. | |
// You could just sit in an infinite loop here, but might as well do something too | |
// Enter the event loop (Note: I advise you asbstract this away with an iterator over events) | |
loop { | |
let event = connection.wait_for_event(); | |
match event { | |
None => { break; } // The window has been closed and/or something went wrong | |
Some(event) => { | |
match event.response_type() { | |
xcb::EXPOSE => { | |
println!("A wild window appeared!"); | |
} | |
xcb::KEY_PRESS => { | |
// You need to cast between event types here | |
// The origin of that requirement is that C uses pointers to structs to fake polymorphism | |
// Unfortunately since we're using bindings we sort of inherit that but you can just | |
// ignore the casting unless there's some attribute you need that isn't on the normal event struct | |
let key_press : &xcb::KeyPressEvent = unsafe { | |
xcb::cast_event(&event) | |
}; | |
// This 9 is the key code for the escape key on my keyboard. If you actually want to | |
// check if the escape key was pressed you need to use another part of xcb to load | |
// a key mapping that will convert dumb keycodes into a locale-specific key. | |
if key_press.detail() == 9 { | |
break; | |
} | |
} | |
_ => {} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment