如何使用 rust-xcb 获得 X window class 给定的 window ID?
How do I get the X window class given a window ID with rust-xcb?
我正在尝试使用 rust-xcb 获取 window 的 class,给定 window 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
and of the xcb_get_property_reply_t
它包装的内容。
我查看了 但我不知道 Rust 中的 ctypes
是什么。我尝试将 &[c_void]
转换为 &str
或 String
:
...
Ok(reply) => {
let len = reply.value_len() as usize;
let buf = reply.value() as &str;
println!("{}", buf.slice_unchecked(0, len)); // this seems redundant
}
...
但是 returns
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('[=10=]').collect();
results[0].to_string()
}
这个问题主要分为三个部分:
- 我输入
xproto::get_property()
in a loop so I could check reply.bytes_after()
并相应地调整long_offset
。我认为适当的 long_length
通常只会读一次,但只是为了安全。
- 正如@peter-hall所说,转换
&[u8] -> String
应该使用String::from_utf8
来完成,这需要一个Vec
;所以我 let mut buf = Vec::new()
和 buf.extend_from_slice
在使用 String::from_utf8(buf).unwrap()
创建结果字符串之前循环
- 根据this random page WM_CLASS实际上是两个连续的以null结尾的字符串,所以我将结果除以
[=21=]
并获取第一个值。
我可能只是找错了地方,但 xcb 的文档绝对糟糕..
我正在尝试使用 rust-xcb 获取 window 的 class,给定 window 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
and of the xcb_get_property_reply_t
它包装的内容。
我查看了 ctypes
是什么。我尝试将 &[c_void]
转换为 &str
或 String
:
...
Ok(reply) => {
let len = reply.value_len() as usize;
let buf = reply.value() as &str;
println!("{}", buf.slice_unchecked(0, len)); // this seems redundant
}
...
但是 returns
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('[=10=]').collect();
results[0].to_string()
}
这个问题主要分为三个部分:
- 我输入
xproto::get_property()
in a loop so I could checkreply.bytes_after()
并相应地调整long_offset
。我认为适当的long_length
通常只会读一次,但只是为了安全。 - 正如@peter-hall所说,转换
&[u8] -> String
应该使用String::from_utf8
来完成,这需要一个Vec
;所以我let mut buf = Vec::new()
和buf.extend_from_slice
在使用String::from_utf8(buf).unwrap()
创建结果字符串之前循环
- 根据this random page WM_CLASS实际上是两个连续的以null结尾的字符串,所以我将结果除以
[=21=]
并获取第一个值。
我可能只是找错了地方,但 xcb 的文档绝对糟糕..