X11/Xlib/xcb: для создания окна требуется граничный пиксель, если указана цветовая карта. Почему?

При создании X-окна с использованием Xlib или xcb я обнаружил, что должен предоставить атрибут пикселя границы, если я хочу предоставить карту цветов. Это требование кажется мне странным, поскольку я знаю, как связаны эти два атрибута, и мне было интересно, может ли кто-нибудь поделиться своим пониманием того, почему это так.

В двух приведенных ниже примерах создается окно X с глубиной 32 и визуальным классом True Color. В обоих примерах, если маска для карты цветов удаляется вместе с соответствующим значением, я получаю неожиданное поведение в программе.

В xcb я получаю ошибку BadMatch при проверке файла cookie, тогда как в примере Xlib окно создается успешно, но не отображается.

Может ли кто-нибудь объяснить, почему ни Xlib, ни xcb не работают без указания атрибута пикселя границы, а также почему каждая библиотека проявляет ошибку по-разному?

Xlib.c:

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;
}

xcb.c:

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;
}

person djrollins    schedule 04.04.2017    source источник


Ответы (1)


Я только что попробовал вашу программу, и она не работает, даже если я не укажу цветовую карту, поэтому я думаю, что цветовая карта не связана с вашей проблемой.

Я не совсем уверен, но я предполагаю, что растровое изображение границы по умолчанию — XCB_COPY_FROM_PARENT, и оно должно соответствовать визуальному виду и глубине окна. Но вы устанавливаете визуал и глубину (отличные от родительских). Теперь визуальная граница или глубина отличаются от окна, поэтому вы получаете BadMatch.

Указав цвет пикселя границы, X создает растровое изображение с соответствующими атрибутами и устанавливает его в качестве растрового изображения границы, и все снова работает.

person rodrigo    schedule 04.04.2017
comment
Спасибо за дальнейшее расследование. Цветовая карта, очевидно, была отвлекающим маневром. Ваше объяснение звучит вполне правдоподобно, и я склонен полагать, что это так. Однако я не нашел ничего общего с этим в документации. Я приму это как ответ. Спасибо! - person djrollins; 05.04.2017