casting - 如何使用 rust-xcb 获取给定窗口 ID 的 X 窗口类?

标签 casting rust x11 xcb

我正在尝试使用 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它包裹着。

我看了this answer in 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('\0').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) 创建结果字符串之前,我让 mut buf = Vec::new()buf.extend_from_slice 结束循环。解包()
  3. 根据 this random page WM_CLASS 实际上是两个连续的以 null 结尾的字符串,所以我将结果拆分为 \0 并获取第一个值。

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

关于casting - 如何使用 rust-xcb 获取给定窗口 ID 的 X 窗口类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44833160/

相关文章:

c - 如何使用 X11 复制到剪贴板?

c++ - 设置对话框窗口的边框颜色

sql - 将 getdate() 转换为 int

c# - LINQ to Entities 查询不支持转换为十进制

c# - 通过使用转换器来转换对象来绑定(bind)到任意 Dictionary<,>

python-3.x - 如何解决 XStartTimeoutError : Failed to start X on display ":1013" error

java - Long 和 Integer 类转换

serialization - 将字符串或枚举放入 LMDB

rust - 悬挂指针安全吗?

rust - 如何使用 Polars::prelude::fold_exprs 累积列中的行?