Невозможно рисовать полигоны с помощью XCB в C

Только начал с программирования XCB с C. Я написал этот код, который создаст окно и нарисует несколько точек и прямоугольник:

#include <stdlib.h>
#include <stdio.h>
#include <xcb/xcb.h>

int main() {
    xcb_connection_t *connection = xcb_connect(NULL, NULL);
    if (xcb_connection_has_error(connection)) {
        printf("Error setting up connection to X\n");
        exit(1);
    }
    const xcb_setup_t *setup = xcb_get_setup(connection);
    xcb_screen_t *screen = xcb_setup_roots_iterator(setup).data;

    // Create wndow
    xcb_window_t window_id = xcb_generate_id(connection);
    uint32_t prop_name = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    uint32_t prop_value[2];
    prop_value[0] = screen->white_pixel;
    prop_value[1] = XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_EXPOSURE;
    xcb_create_window(connection, screen->root_depth, window_id, screen->root, 100, 100, 500, 400, 1,
                            XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->root_visual, prop_name, &prop_value);
    xcb_map_window(connection, window_id);
    xcb_flush(connection);

    uint32_t gc_value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
    uint32_t gc_value_list[2];
    gc_value_list[0] = screen->black_pixel;
    gc_value_list[1] = 0;
    xcb_drawable_t drawable_window = screen->root;
    xcb_gcontext_t context_id = xcb_generate_id(connection);
    xcb_void_cookie_t cookie = xcb_create_gc(connection, context_id, drawable_window, gc_value_mask, gc_value_list);

    // Create polygons
    xcb_point_t points[5] = {{10, 10}, {10, 50}, {40, 70}, {70, 40}, {50, 10}};
    xcb_rectangle_t rect = {50, 50, 100, 50};

    // Main loop
    xcb_generic_event_t *event;
    while ((event = xcb_wait_for_event(connection))) {
        switch (event->response_type) {
            case XCB_KEY_PRESS:
                break;
            case XCB_BUTTON_PRESS:
                break;
            case XCB_EXPOSE:
                printf("Expose event called\n");
                // Draw polygons
                xcb_poly_point(connection, XCB_COORD_MODE_ORIGIN, drawable_window, context_id, 4, points);
                xcb_poly_fill_rectangle(connection, drawable_window, context_id, 1, &rect);
                xcb_flush(connection);
            default:
                break;
        }
        free(event);
    }

    return 0;
}

Он скомпилирован правильно, и во время выполнения не было никаких предупреждений или ошибок. Но я просто получаю окно без графики. Что я делаю не так?


c xcb
person Puspam    schedule 17.09.2020    source источник
comment
Вы получаете событие разоблачения?   -  person user253751    schedule 17.09.2020
comment
Да, я понимаю. После запуска программы и всякий раз, когда я изменяю размер окна, в терминале печатается Expose event called, что показывает, что событие expose вызывается.   -  person Puspam    schedule 17.09.2020


Ответы (2)


Я думаю, что ваши xcb_poly_fill_rectangle() и т. д. пытаются рисовать в корневом окне. По крайней мере, вы передаете screen->root в качестве аргумента drawable. У меня работает, если я передам window_id здесь.

Я действительно не уверен, зачем XCB нужны все эти различные аргументы контекста, и точные функции каждого из них, похоже, недостаточно документированы.

person Kevin Boone    schedule 17.09.2020
comment
Какой аргумент вас смущает? context_id — это идентификатор графического контекста (GC) или эквивалент Windows HDC. - person user253751; 17.09.2020
comment
@user253751 user253751 - нет, я думаю, это достаточно справедливо. Я больше привык к такому виду контекстной информации, которая передается в объектах или, по крайней мере, в structs. Куча числовых ручек - это просто так 90-е. - person Kevin Boone; 17.09.2020
comment
Это сетевой протокол. Будете ли вы отправлять все данные контекста на сервер каждый раз, когда рисуете? - person user253751; 23.09.2020
comment
@user253751 user253751 - я ожидаю, что библиотека позаботится об этом низкоуровневом материале, и я бы просто работал над структурой данных, которая инкапсулирует контекст. Например, так работает GTK. Я не говорю, что путь XCB неправильный или хуже, просто я отвык работать на этом уровне. - person Kevin Boone; 23.09.2020

Кевин Бун прав: вы рисуете в корневом окне.

Я внес следующее изменение в вашу программу (это то же самое, что предложил Кевин):

--- t.c.orig    2020-09-18 15:06:38.344441255 +0200
+++ t.c 2020-09-18 15:06:48.104167556 +0200
@@ -26,7 +26,7 @@ int main() {
     uint32_t gc_value_list[2];
     gc_value_list[0] = screen->black_pixel;
     gc_value_list[1] = 0;
-    xcb_drawable_t drawable_window = screen->root;
+    xcb_drawable_t drawable_window = window_id;
     xcb_gcontext_t context_id = xcb_generate_id(connection);
     xcb_void_cookie_t cookie = xcb_create_gc(connection, context_id, drawable_window, gc_value_mask, gc_value_list);

В результате отображается следующее содержимое окна. Вы можете видеть как отображаемый прямоугольник, так и отдельные пиксели:

введите здесь описание изображения

Пожалуйста, не принимайте этот ответ, а ответ Кевина Буна. Я только хотел добавить скриншот.

person Uli Schlachter    schedule 18.09.2020
comment
Это очень щедро с твоей стороны :) - person Kevin Boone; 23.09.2020