I'm trying to use a Cairo surface in xcb-created window. I have a C example as well as Rust XCB and Cairo bindings. I'm almost finished, but this error remains a mystery to me.
My code:
fn find_visual<'a>(conn: &'a xcb::Connection, visual: xcb_visualid_t) -> Option<Visualtype<'a>> {
let setup: Setup<'a> = conn.get_setup();
for screen in setup.roots() {
let d_iter: DepthIterator = screen.allowed_depths();
for depth in d_iter {
for vis in depth.visuals() {
if visual == vis.visual_id() {
println!("Found visual");
return Some(vis)
}
}
}
}
None
}
I call this as:
let visual = find_visual(&conn, screen.root_visual()).unwrap();
And gain errors like this:
src/main.rs:56:19: 56:24 error: `setup` does not live long enough
src/main.rs:56 for screen in setup.roots() {
^~~~~
src/main.rs:54:97: 68:2 note: reference must be valid for the lifetime 'a as defined on the block at 54:96...
src/main.rs:54 fn find_visual<'a>(conn: &'a xcb::Connection, visual: xcb_visualid_t) -> Option<Visualtype<'a>> {
src/main.rs:55 let setup: Setup<'a> = conn.get_setup();
src/main.rs:56 for screen in setup.roots() {
src/main.rs:57 let d_iter: DepthIterator = screen.allowed_depths();
src/main.rs:58 for depth in d_iter {
src/main.rs:59 for vis in depth.visuals() {
...
src/main.rs:55:45: 68:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 55:44
src/main.rs:55 let setup: Setup<'a> = conn.get_setup();
src/main.rs:56 for screen in setup.roots() {
src/main.rs:57 let d_iter: DepthIterator = screen.allowed_depths();
src/main.rs:58 for depth in d_iter {
src/main.rs:59 for vis in depth.visuals() {
src/main.rs:60 if visual == vis.visual_id() {
...
And the same errors for screen
and depth
variables.
Can someone explain - why "setup
does not live long enough"? As I understand, setup
will be destroyed when function return
Option, and it can be used in function without limitations.
get_setup()
code:
pub fn get_setup(&self) -> Setup {
unsafe {
let setup = xcb_get_setup(self.c);
if setup.is_null() {
panic!("NULL setup on connection")
}
mem::transmute(setup)
}
}
It looks like the lifetime annotations of the bindings are faulty. Here's roots()
:
impl<'a> Screen<'a> {
pub fn roots(&self) -> ScreenIterator {
unsafe {
xcb_setup_roots_iterator(self.ptr)
}
}
}
Note that because there are no annotations on the function, this is implicitly annotated as
impl<'a> Screen<'a> {
pub fn <'b> roots(&'b self) -> ScreenIterator<'b> {
unsafe {
xcb_setup_roots_iterator(self.ptr)
}
}
}
And this is wrong. The returned ScreenIterator
needs to be explicitly annotated with lifetime 'a
instead, which is the lifetime of the underlying connection, and XCB appears to have the convention that all the pointers it hands out are bound by lifetime to the lifetime of the connection (see the comment for the wrapper type base::StructPtr
. This means the generator scripts need to be adjusted to account for this. You should file an issue with the crate.
upd from requestor: @SebastianRedl was right. Problem is in unset lifetimes in xcb crate for all functions which returns Iterators. Next lifetime changes in rust-xcb crate allows to compile code successfully:
impl<'a> Setup<'a> {
pub fn roots(&self) -> ScreenIterator<'a> {
unsafe {
xcb_setup_roots_iterator(self.ptr)
}
}
}
impl<'a> Depth<'a> {
pub fn visuals(&self) -> VisualtypeIterator<'a> {
unsafe {
xcb_depth_visuals_iterator(self.ptr)
}
}
}
impl<'a> Screen<'a> {
pub fn allowed_depths(&self) -> DepthIterator<'a> {
unsafe {
xcb_screen_allowed_depths_iterator(self.ptr)
}
}
}