When creating an X window using either Xlib or xcb, I have found that I must provide the border pixel attribute if I want to provide a colormap. This requirement seems strange to me as I'm note sure how these two attributes relate and I wondered if anyone could share some insight as to why this is the case.
The two examples below create an X window with a depth of 32 and a True Color visual class. In both examples, if the mask for the color map is removed along with the corresponding value, I get unexpected behaviour in the program.
In xcb I get a BadMatch
error when the cookie is checked, whereas in the Xlib example the window creates successfully but is not mapped.
Can someone explain why neither Xlib or xcb work without specifying the Border Pixel attribute and also why each library manifests the error in different ways?
int main()
{
Display *display = XOpenDisplay(NULL);
if (!display) {
/* TODO(djr): Logging */
fputs("X11: Unable to create connection to display server", stderr);
return -1;
}
int screen = DefaultScreen(display);
Window root = RootWindow(display, screen);
XVisualInfo vinfo = {0};
if (!XMatchVisualInfo(display, screen, 32, TrueColor, &vinfo)) {
/* TODO(djr): Logging */
fputs("X11: Unable to find supported visual info", stderr);
return -1;
}
Colormap colormap = XCreateColormap(
display, root, vinfo.visual, AllocNone);
const unsigned long wamask = CWColormap | CWBorderPixel;
XSetWindowAttributes wa;
wa.colormap = colormap;
wa.border_pixel = WhitePixel(display, screen);
Window window = XCreateWindow(
display,
root,
0, 0,
1600, 900,
1, /* border width */
vinfo.depth,
InputOutput,
vinfo.visual,
wamask,
&wa);
if (!window) {
/* TODO(djr): Logging */
fputs("X11: Unable to create window", stderr);
return -1;
}
XMapWindow(display, window);
XFlush(display);
pause();
XCloseDisplay(display);
return 0;
}
int main()
{
xcb_connection_t *connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(connection)) {
fprintf(stderr, "ERROR: failed to connection to X server\n");
return -1;
}
const xcb_setup_t *setup = xcb_get_setup(connection);
xcb_screen_t *screen = xcb_setup_roots_iterator(setup).data;
xcb_depth_iterator_t depth_iter = xcb_screen_allowed_depths_iterator(screen);
xcb_depth_t *depth = NULL;
while (depth_iter.rem) {
if (depth_iter.data->depth == 32 && depth_iter.data->visuals_len) {
depth = depth_iter.data;
break;
}
xcb_depth_next(&depth_iter);
}
if (!depth) {
fprintf(stderr, "ERROR: screen does not support 32 bit color depth\n");
xcb_disconnect(connection);
return -1;
}
xcb_visualtype_iterator_t visual_iter = xcb_depth_visuals_iterator(depth);
xcb_visualtype_t *visual = NULL;
while (visual_iter.rem) {
if (visual_iter.data->_class == XCB_VISUAL_CLASS_TRUE_COLOR) {
visual = visual_iter.data;
break;
}
xcb_visualtype_next(&visual_iter);
}
if (!visual) {
fprintf(stderr, "ERROR: screen does not support True Color\n");
xcb_disconnect(connection);
return -1;
}
xcb_colormap_t colormap = xcb_generate_id(connection);
xcb_void_cookie_t cookie = xcb_create_colormap_checked(
connection,
XCB_COLORMAP_ALLOC_NONE,
colormap,
screen->root,
visual->visual_id);
xcb_generic_error_t *error = xcb_request_check(connection, cookie);
if (error) {
fprintf(stderr, "ERROR: failed to create colormap: %s\n", xcb_errors[error->error_code]);
xcb_disconnect(connection);
return -1;
}
unsigned int cw_mask = XCB_CW_COLORMAP | XCB_CW_BORDER_PIXEL;
unsigned int cw_values[] = { screen->white_pixel, colormap };
xcb_window_t window = xcb_generate_id(connection);
cookie = xcb_create_window_checked(
connection,
depth->depth,
window,
screen->root,
0, 0,
1600, 900,
1,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
visual->visual_id,
cw_mask,
cw_values);
error = xcb_request_check(connection, cookie);
if (error) {
fprintf(stderr, "ERROR: failed to create window: %s\n", xcb_errors[error->error_code]);
xcb_disconnect(connection);
return -1;
}
xcb_map_window(connection, window);
xcb_flush(connection);
pause();
xcb_disconnect(connection);
return 0;
}
I just tried your program and it fails even if I don't specify the colormap, so I think that the colormap is unrelated to your problem.
I'm not totally sure, but my guess is that the default border pixmap is XCB_COPY_FROM_PARENT
, and that must match the window visual and depth. But you are setting the visual and depth (different than those of the parent). Now, the border visual or depth is different than that of the window, so you get a BadMatch.
By specifying a border pixel color, X creates a pixmap of appropriate attributes and sets it as the border pixmap and everything works again.