I am trying to put a simple test image to a pixmap (and then to a screen). However, I always get a length error. From all the C examples I could find (not many, none for Rust), this should work. I assume that I am getting something wrong. Any help is appreciated. Here is my code:
const B: u8 = 0x00; // background
const C: u8 = 0xCC; // corner
const E: u8 = 0xEE; // edge
const F: u8 = 0xFF; // foreground
const CROSSIMG: [u8; 120] = [
B, B, B, B, B, B, B, B, B, B, // 0
B, B, B, C, E, E, C, B, B, B, // 1
B, B, B, E, F, F, E, B, B, B, // 2
B, C, E, E, F, F, E, E, C, B, // 3
B, E, F, F, F, F, F, F, E, B, // 4
B, E, F, F, F, F, F, F, E, B, // 5
B, C, E, E, F, F, E, E, C, B, // 6
B, B, B, E, F, F, E, B, B, B, // 7
B, B, B, E, F, F, E, B, B, B, // 8
B, B, B, E, F, F, E, B, B, B, // 9
B, B, B, C, E, E, C, B, B, B, // 10
B, B, B, B, B, B, B, B, B, B, // 11
];
let pix_id = conn.generate_id();
conn.check_request(conn.send_request_checked(&x::CreatePixmap {
depth: 8,
pid: pix_id,
drawable: x::Drawable::Window(screen.root()),
width: 20,
height: 20,
}))?;
let context = conn.generate_id();
let cookie = conn.send_request_checked(&x::CreateGc {
cid: context,
drawable: xcb::x::Drawable::Pixmap(pix_id),
value_list: &[],
});
conn.check_request(cookie)?;
println!("{:?}", context.resource_id());
let req = &x::PutImage {
format: x::ImageFormat::XyPixmap,
drawable: x::Drawable::Pixmap(pix_id),
gc: context,
width: 10,
height: 12,
dst_x: 0,
dst_y: 0,
left_pad: 0,
depth: 8,
data: &CROSSIMG,
};
println!("request: {:?}, length: {:?} ", req, 0);
let cookie = conn.send_request_checked(req);
conn.check_request(cookie)?;
The error returned looks like that:
Error: Protocol(X(Length(RequestError { response_type: 0, error_code: 16, sequence: 17, bad_value: 37748738, minor_opcode: 0, major_opcode: 72, pad: 1 }), Some("x::PutImage")))
I bet that you would get similar output than me when running the following:
$ xdpyinfo | grep 'depth 8'
depth 8, bits_per_pixel 8, scanline_pad 32
This means that for depth 8
, every image line must be aligned to a multiple of four bytes. Thus, for a PutImage with width 10, you need 12 bytes per line and your total pixel data needs to be 12*12 bytes.
The actual length check in the X11 server likely is this one:
if ((bytes_to_int32(lengthProto * stuff->height) +
bytes_to_int32(sizeof(xPutImageReq))) != client->req_len)
return BadLength;
lengthProto
comes (in your case, XYPixmap
) from this code in the same function:
length = BitmapBytePad(stuff->width + stuff->leftPad);
length *= stuff->depth;
Relevant part of the protocol reference:
Each scanline is padded to a multiple of bits as given by bitmap-scanline-pad. The pad bits are of arbitrary value.
You are specifying a pixel format of x::ImageFormat::XyPixmap
, while you actually want ZPixmap
.
ZPixmap
is the "usual" format that you expect (in this case: One byte per pixel). T
From the specification:
If a pixmap is represented in XY format, each plane is represented as a bitmap, and the planes appear from most significant to least significant in bit order with no padding between planes.
For more information about this, see What is the difference between XYPixmap, ZPixmap, XImage, XShmImage and Bitmap in X? . Best description for XY format from that (IMHO):
The more practical answer is "this is not the image format you are looking for".