如何获得带有 rust-xcb 的窗口 ID 的 X 窗口类?



我正在尝试使用 rust-xcb 来获取给定窗口 ID 的窗口类。

fn get_class(conn: &xcb::Connection, id: &i32) {
let window: xcb::xproto::Window = *id as u32;
let class_prop: xcb::xproto::Atom = 67; // XCB_ATOM_WM_CLASS from xproto.h
let cookie = xcb::xproto::get_property(&conn, false, window, class_prop, 0, 0, 2);
match cookie.get_reply() {
Ok(reply) => {
let x: &[std::os::raw::c_void] = reply.value();
println!("reply is {:?}", x[0]);
}   
Err(err) => println!("err {:?}", err),
}
}

文档有点稀疏,并没有太大的帮助,尽管我确实发现了关于GetPropertyReply和它包装xcb_get_property_reply_t的一点。

我在 JavaScript 中查看了这个答案,但我不知道 Rust 中ctypes等价物是什么。我尝试只是将&[c_void]转换为&strString

...
Ok(reply) => {
let len = reply.value_len() as usize;
let buf = reply.value() as &str;
println!("{}", buf.slice_unchecked(0, len)); // this seems redundant
}   
...

但它返回

error: non-scalar cast: `&[_]` as `&str`

我尝试将&[c_void]铸造为&[u8],然后将Vec收集到String中,这有点有效:

...
Ok(reply) => {
let value : &[u8] = reply.value();
let buf : String = value.into_iter().map(|i| *i as char).collect();
println!("t{:?}", buf);
}
...

例如,当我在Chrome上使用xprop时,我看到"google-chrome",但对我来说它只显示"google-c",而"roxterm"显示为"roxterm\u{0}"。我猜"\u{0}"与 Unicode 相关,但我不确定,我也不知道为什么要连接东西。也许我必须再次检查回复?

这是我更新的函数:

fn get_class(conn: &Connection, id: &i32) -> String {
let window: xproto::Window = *id as u32;
let long_length: u32 = 8;
let mut long_offset: u32 = 0;
let mut buf = Vec::new();
loop {
let cookie = xproto::get_property(
&conn,
false,
window,
xproto::ATOM_WM_CLASS,
xproto::ATOM_STRING,
long_offset,
long_length,
);
match cookie.get_reply() {
Ok(reply) => {
let value: &[u8] = reply.value();
buf.extend_from_slice(value);
match reply.bytes_after() {
0 => break,
_ => {
let len = reply.value_len();
long_offset += len / 4;
}   
}
}   
Err(err) => {
println!("{:?}", err);
break;
}   
}
}
let result = String::from_utf8(buf).unwrap();
let results: Vec<&str> = result.split('').collect();
results[0].to_string()
}

这个问题有三个主要部分:

  1. 我把xproto::get_property()放在一个循环中,这样我就可以检查reply.bytes_after()并相应地调整long_offset。我认为通过适当的long_length通常只会有一次阅读,但只是为了安全。
  2. 正如 @peter-hall 所说,转换&[u8] -> String应该使用String::from_utf8来完成,这需要Vec;所以我在创建带有String::from_utf8(buf).unwrap()的结果字符串之前let mut buf = Vec::new()buf.extend_from_slice遍历循环
  3. 根据这个随机页面WM_CLASS实际上是两个连续的以 null 结尾的字符串,所以我将结果拆分为并获取第一个值。

我可能只是找错了地方,但 xcb 有绝对糟糕的文档。

最新更新