简体   繁体   English

如何使用rust-xcb获得具有窗口ID的X窗口类?

[英]How do I get the X window class given a window ID with rust-xcb?

I'm trying to use rust-xcb to get a window's class given a window ID. 我正在尝试使用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),
    }
}

The documentation is kind of sparse and hasn't been incredibly helpful, though I did find this bit about the GetPropertyReply and of the xcb_get_property_reply_t it wraps. 尽管我确实发现了有关GetPropertyReply和它包装的xcb_get_property_reply_t一些知识,但是该文档还是比较稀疏的,并没有得到很大的帮助。

I looked at this answer in JavaScript but I don't know what the ctypes equivalent in Rust is. 用JavaScript看了这个答案,但是不知道Rust中的ctypes是什么。 I tried just casting the &[c_void] as a &str or String : 我尝试将&[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
 }   
 ...

but it returns 但它返回

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

I tried casting the &[c_void] as a &[u8] and then collecting the Vec into a String , which sort of works: 我尝试将&[c_void]&[u8] ,然后将Vec收集到String&[c_void]工作如下:

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

but I'm now getting weird results. 但是我现在得到的结果很奇怪。 for example , when I use xprop on Chrome I see "google-chrome" but for me it is only showing "google-c", and "roxterm" is showing up as "roxterm\\u{0}\u0026quot;. 例如,当我在Chrome上使用xprop ,我看到“ google-chrome”,但对我来说它仅显示“ google-c”,而“ roxterm”则显示为“ roxterm \\ u {0}”。 I'm guessing "\\u{0}\u0026quot; is something Unicode related but I'm not sure, and I don't know why stuff is being concatenated either. 我猜“ \\ u {0}”与Unicode有关,但我不确定,我也不知道为什么东西也要串联起来。 Maybe I have to check the reply again? 也许我必须再次检查回复?

Here's my updated function: 这是我更新的功能:

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()
}

There were three main parts to this question: 这个问题包括三个主要部分:

  1. I put xproto::get_property() in a loop so I could check reply.bytes_after() and accordingly adjust long_offset . 我将xproto::get_property()放入循环中,以便可以检查reply.bytes_after()并相应地调整long_offset I think with an appropriate long_length there will usually only be one read, but just being safe. 我认为使用适当的long_length通常只会读取一次,但只是安全起见。
  2. As @peter-hall said, converting &[u8] -> String should be done using String::from_utf8 , which needs a Vec ; 正如@ peter-hall所说,转换&[u8] -> String应该使用String::from_utf8 ,这需要一个Vec so I let mut buf = Vec::new() and buf.extend_from_slice over the loop before creating the result string with String::from_utf8(buf).unwrap() 所以我在使用String::from_utf8(buf).unwrap()创建结果字符串之前, let mut buf = Vec::new()buf.extend_from_slice遍历循环。
  3. According to this random page WM_CLASS is actually two consecutive null-terminated strings, so I split the result by \\0 and grab the first value. 根据此随机页面, WM_CLASS实际上是两个连续的以空字符结尾的字符串,因此我将结果除以\\0并获取第一个值。

I might've just been looking in the wrong place, but xcb has absolutely terrible documentation.. 我可能一直在找错地方,但是xcb的文档绝对糟糕。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM