do not edit — generated by btf.
git.druid.rocksindexmilitantprogrammerastral_canvassrc/platform/x11.c

src/platform/x11.c


#include "platform.h"
#include "../input/input.h"
#include "shm.h"
 
#include <errno.h>
#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
 
#include <sys/ipc.h>
#include <sys/shm.h>
 
#include <xcb/xcb.h>
#include <xcb/shm.h>
#include <xcb/xkb.h>
#include <xcb/xcb_cursor.h>
#include <xcb/xcb_icccm.h>
#include <xkbcommon/xkbcommon-x11.h>
 
#define VK_USE_PLATFORM_XCB_KHR
#include <vulkan/vulkan.h>
 
/*
 * X11/xcb backend, stored in Platform.impl. Owns the connection, window,
 * graphics context, MIT-SHM (or SysV / PutImage fallback) pixel buffer,
 * and xkbcommon-x11 keyboard state.
 *
 * Buffer attach order: memfd + xcb_shm_attach_fd, else SysV shmget +
 * xcb_shm_attach, else a malloc'd buffer uploaded with PutImage in
 * strips. shm_fd / shmid are mutually exclusive; the unused one is -1.
 */
typedef struct {
    Platform *platform;
    xcb_connection_t *connection;
    xcb_screen_t *screen;
    xcb_window_t window;
    xcb_gcontext_t graphicsContext;
    uint8_t depth;
 
    xcb_atom_t wmProtocols;
    xcb_atom_t wmDeleteWindow;
    xcb_atom_t netWmName;
    xcb_atom_t utf8String;
    xcb_atom_t netWmPid;
 
    xcb_cursor_context_t *cursorContext;
    xcb_cursor_t cursor;
 
    int shmFileDescriptor;
    int shmId;
    size_t shmSize;
    xcb_shm_seg_t shmSegment;
    bool useShm;
 
    InputXkb xkb;
    uint8_t xkbBaseEvent;
    int32_t xkbDeviceId;
    bool keyDown[256];
} X11;
 
static xcb_atom_t intern_atom(xcb_connection_t *conn, const char *name)
{
    xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn, 0, (uint16_t)strlen(name), name);
    xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
    xcb_atom_t atom = reply ? reply->atom : XCB_ATOM_NONE;
    free(reply);
    return atom;
}
 
static void x11Push(X11 *x11, Event ev)
{
    eventQueuePush(&x11->platform->events, ev);
}
 
static void x11FreeBuffer(X11 *x11)
{
    if (x11->useShm && x11->shmSegment) {
        xcb_shm_detach(x11->connection, x11->shmSegment);
        x11->shmSegment = 0;
    }
    if (x11->shmId >= 0) {
        if (x11->platform->pixels)
            shmdt(x11->platform->pixels);
        x11->shmId = -1;
    } else if (x11->shmFileDescriptor >= 0) {
        shm_free(x11->shmFileDescriptor, x11->platform->pixels, x11->shmSize);
        x11->shmFileDescriptor = -1;
    } else {
        free(x11->platform->pixels);
    }
    x11->platform->pixels = NULL;
    x11->shmSize = 0;
}
 
static int x11AllocBuffer(X11 *x11, int width, int height)
{
    if (width < 1)
        width = 1;
    if (height < 1)
        height = 1;
 
    x11FreeBuffer(x11);
 
    size_t size = (size_t)width * (size_t)height * 4;
    x11->platform->width = width;
    x11->platform->height = height;
    x11->platform->bufferWidth = width;
    x11->platform->bufferHeight = height;
    x11->platform->stride = width * 4;
 
    if (x11->useShm) {
        x11->shmSegment = xcb_generate_id(x11->connection);
        int fd = shm_alloc(size, (void **)&x11->platform->pixels);
        if (fd >= 0) {
            int send_fd = dup(fd);
            if (send_fd >= 0) {
                xcb_void_cookie_t cookie = xcb_shm_attach_fd_checked(x11->connection, x11->shmSegment, send_fd, 0);
                xcb_generic_error_t *err = xcb_request_check(x11->connection, cookie);
                if (!err) {
                    x11->shmFileDescriptor = fd;
                    x11->shmSize = size;
                    x11->shmId = -1;
                    return 0;
                }
                free(err);
            }
            shm_free(fd, x11->platform->pixels, size);
            x11->platform->pixels = NULL;
        }
 
        int shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0600);
        if (shmid >= 0) {
            void *map = shmat(shmid, NULL, 0);
            shmctl(shmid, IPC_RMID, NULL);
            if (map != (void *)-1) {
                xcb_void_cookie_t cookie = xcb_shm_attach_checked(x11->connection, x11->shmSegment, (uint32_t)shmid, 0);
                xcb_generic_error_t *err = xcb_request_check(x11->connection, cookie);
                if (!err) {
                    memset(map, 0, size);
                    x11->platform->pixels = (uint32_t *)map;
                    x11->shmId = shmid;
                    x11->shmSize = size;
                    x11->shmFileDescriptor = -1;
                    return 0;
                }
                free(err);
                shmdt(map);
            }
        }
        fprintf(stderr, "x11: shm attach failed, falling back to PutImage\n");
        x11->useShm = false;
        x11->shmSegment = 0;
    }
 
    x11->platform->pixels = (uint32_t*)calloc(1, size);
    if (!x11->platform->pixels)
        return -1;
    x11->shmSize = size;
    x11->shmFileDescriptor = -1;
    x11->shmId = -1;
    return 0;
}
 
static int x11ReloadKeymap(X11 *x11)
{
    struct xkb_keymap *keymap = xkb_x11_keymap_new_from_device(
        x11->xkb.context, x11->connection, x11->xkbDeviceId, XKB_KEYMAP_COMPILE_NO_FLAGS);
    if (!keymap)
        return -1;
    struct xkb_state *state = xkb_x11_state_new_from_device(keymap, x11->connection, x11->xkbDeviceId);
    if (!state) {
        xkb_keymap_unref(keymap);
        return -1;
    }
    inputXkbSetKeymap(&x11->xkb, keymap, state);
    x11->platform->modifiers = inputModifiers(&x11->xkb);
    return 0;
}
 
static int x11SetupXkb(X11 *x11)
{
    uint8_t base_error = 0;
    if (!xkb_x11_setup_xkb_extension(x11->connection,
                                     XKB_X11_MIN_MAJOR_XKB_VERSION,
                                     XKB_X11_MIN_MINOR_XKB_VERSION,
                                     XKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,
                                     NULL, NULL, &x11->xkbBaseEvent, &base_error)) {
        fprintf(stderr, "x11: XKB extension unavailable\n");
        return -1;
    }
 
    x11->xkbDeviceId = xkb_x11_get_core_keyboard_device_id(x11->connection);
    if (x11->xkbDeviceId == -1)
        return -1;
 
    if (inputXkbInit(&x11->xkb) < 0)
        return -1;
    if (x11ReloadKeymap(x11) < 0)
        return -1;
 
    const uint16_t events =
        XCB_XKB_EVENT_TYPE_NEW_KEYBOARD_NOTIFY |
        XCB_XKB_EVENT_TYPE_MAP_NOTIFY |
        XCB_XKB_EVENT_TYPE_STATE_NOTIFY;
    xcb_xkb_select_events(x11->connection, (xcb_xkb_device_spec_t)x11->xkbDeviceId,
                          events, 0, events, 0, 0, NULL);
 
    xcb_xkb_per_client_flags(x11->connection, (xcb_xkb_device_spec_t)x11->xkbDeviceId,
                             XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
                             XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
                             0, 0, 0);
    return 0;
}
 
static uint32_t x11ScrollButton(uint8_t detail, PointerEvent *pe)
{
    switch (detail) {
    case 4:
        pe->axis = AXIS_VERTICAL;
        pe->axisValue = -1.0;
        pe->axisSteps = -1;
        return 1;
    case 5:
        pe->axis = AXIS_VERTICAL;
        pe->axisValue = 1.0;
        pe->axisSteps = 1;
        return 1;
    case 6:
        pe->axis = AXIS_HORIZONTAL;
        pe->axisValue = -1.0;
        pe->axisSteps = -1;
        return 1;
    case 7:
        pe->axis = AXIS_HORIZONTAL;
        pe->axisValue = 1.0;
        pe->axisSteps = 1;
        return 1;
    default:
        return 0;
    }
}
 
static uint32_t x11DetailToButton(uint8_t detail)
{
    switch (detail) {
    case 1: return BUTTON_LEFT;
    case 2: return BUTTON_MIDDLE;
    case 3: return BUTTON_RIGHT;
    case 8: return BUTTON_BACK;
    case 9: return BUTTON_FORWARD;
    default: return 0;
    }
}
 
static void x11PointerEvent(X11 *x11, uint32_t kind, uint32_t time, int16_t px, int16_t py)
{
    Event ev = {0};
    ev.kind = EVENT_POINTER;
    ev.pointer.kind = kind;
    ev.pointer.timeMilliseconds = time;
    ev.pointer.x = (double)px;
    ev.pointer.y = (double)py;
    ev.pointer.buttons = x11->platform->buttons;
    ev.pointer.modifiers = x11->platform->modifiers;
    x11->platform->mouseX = ev.pointer.x;
    x11->platform->mouseY = ev.pointer.y;
    x11Push(x11, ev);
}
 
static void x11HandleXkb(X11 *x11, xcb_generic_event_t *ge)
{
    xcb_xkb_state_notify_event_t *ne = (xcb_xkb_state_notify_event_t *)ge;
    switch (ne->xkbType) {
    case XCB_XKB_NEW_KEYBOARD_NOTIFY: {
        xcb_xkb_new_keyboard_notify_event_t *e = (xcb_xkb_new_keyboard_notify_event_t *)ge;
        if (e->deviceID == x11->xkbDeviceId && (e->changed & XCB_XKB_NKN_DETAIL_KEYCODES))
            x11ReloadKeymap(x11);
        break;
    }
    case XCB_XKB_MAP_NOTIFY:
        x11ReloadKeymap(x11);
        break;
    case XCB_XKB_STATE_NOTIFY:
        if (x11->xkb.state) {
            xkb_state_update_mask(x11->xkb.state,
                                  ne->baseMods, ne->latchedMods, ne->lockedMods,
                                  (uint32_t)ne->baseGroup, (uint32_t)ne->latchedGroup,
                                  ne->lockedGroup);
            x11->platform->modifiers = inputModifiers(&x11->xkb);
        }
        break;
    default:
        break;
    }
}
 
static void x11HandleEvent(X11 *x11, xcb_generic_event_t *ge)
{
    uint8_t type = ge->response_type & ~0x80;
    if (type == 0) {
        xcb_generic_error_t *err = (xcb_generic_error_t *)ge;
        fprintf(stderr, "x11 error: code=%u major=%u minor=%u\n",
                err->error_code, err->major_code, err->minor_code);
        return;
    }
    if (type == x11->xkbBaseEvent) {
        x11HandleXkb(x11, ge);
        return;
    }
 
    switch (type) {
    case XCB_EXPOSE:
        x11Push(x11, (Event){ .kind = EVENT_EXPOSE });
        break;
 
    case XCB_CONFIGURE_NOTIFY: {
        xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *)ge;
        if (e->window != x11->window)
            break;
        if (e->width == x11->platform->width && e->height == x11->platform->height)
            break;
        if (x11AllocBuffer(x11, e->width, e->height) < 0)
            break;
        Event ev = { .kind = EVENT_RESIZE };
        ev.resize.width = x11->platform->width;
        ev.resize.height = x11->platform->height;
        ev.resize.scale = x11->platform->scale;
        x11Push(x11, ev);
        break;
    }
 
    case XCB_CLIENT_MESSAGE: {
        xcb_client_message_event_t *e = (xcb_client_message_event_t *)ge;
        if (e->data.data32[0] == x11->wmDeleteWindow) {
            x11->platform->running = false;
            x11Push(x11, (Event){ .kind = EVENT_QUIT });
        }
        break;
    }
 
    case XCB_FOCUS_IN:
    case XCB_FOCUS_OUT: {
        x11->platform->focused = (type == XCB_FOCUS_IN);
        Event ev = { .kind = EVENT_FOCUS };
        ev.focus.focused = x11->platform->focused;
        x11Push(x11, ev);
        break;
    }
 
    case XCB_ENTER_NOTIFY: {
        xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *)ge;
        x11->platform->pointerInside = true;
        x11PointerEvent(x11, POINTER_ENTER, e->time, e->event_x, e->event_y);
        break;
    }
 
    case XCB_LEAVE_NOTIFY: {
        xcb_leave_notify_event_t *e = (xcb_leave_notify_event_t *)ge;
        x11->platform->pointerInside = false;
        x11PointerEvent(x11, POINTER_LEAVE, e->time, e->event_x, e->event_y);
        break;
    }
 
    case XCB_MOTION_NOTIFY: {
        xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ge;
        x11PointerEvent(x11, POINTER_MOTION, e->time, e->event_x, e->event_y);
        break;
    }
 
    case XCB_BUTTON_PRESS:
    case XCB_BUTTON_RELEASE: {
        xcb_button_press_event_t *e = (xcb_button_press_event_t *)ge;
        bool pressed = (type == XCB_BUTTON_PRESS);
        PointerEvent pe = {0};
        pe.timeMilliseconds = e->time;
        pe.x = e->event_x;
        pe.y = e->event_y;
        pe.modifiers = x11->platform->modifiers;
        x11->platform->mouseX = pe.x;
        x11->platform->mouseY = pe.y;
 
        if (pressed && x11ScrollButton(e->detail, &pe)) {
            pe.kind = POINTER_AXIS;
            pe.axisSource = AXIS_SOURCE_WHEEL;
            pe.buttons = x11->platform->buttons;
            Event ev = { .kind = EVENT_POINTER };
            ev.pointer = pe;
            x11Push(x11, ev);
            break;
        }
 
        uint32_t button = x11DetailToButton(e->detail);
        if (!button)
            break;
        uint8_t mask = buttonMask(button);
        if (pressed)
            x11->platform->buttons |= mask;
        else
            x11->platform->buttons &= (uint8_t)~mask;
        pe.kind = POINTER_BUTTON;
        pe.button = button;
        pe.pressed = pressed;
        pe.buttons = x11->platform->buttons;
        Event ev = { .kind = EVENT_POINTER };
        ev.pointer = pe;
        x11Push(x11, ev);
        break;
    }
 
    case XCB_KEY_PRESS:
    case XCB_KEY_RELEASE: {
        xcb_key_press_event_t *e = (xcb_key_press_event_t *)ge;
        xkb_keycode_t keycode = e->detail;
        bool pressed = (type == XCB_KEY_PRESS);
        bool repeat = false;
        if (keycode < 256) {
            if (pressed && x11->keyDown[keycode])
                repeat = true;
            x11->keyDown[keycode] = pressed;
        }
        Event ev = { .kind = EVENT_KEY };
        input_fill_key(&x11->xkb, &ev.key, keycode, pressed, repeat);
        ev.key.timeMilliseconds = e->time;
        x11->platform->modifiers = ev.key.modifiers;
        x11Push(x11, ev);
        break;
    }
 
    case XCB_MAPPING_NOTIFY:
        break;
 
    default:
        break;
    }
}
 
static int x11Fd(Platform *platform)
{
    X11 *x11 = (X11*)platform->implementation;
    return xcb_get_file_descriptor(x11->connection);
}
 
static int x11Flush(Platform *platform)
{
    X11 *x11 = (X11*)platform->implementation;
    return xcb_flush(x11->connection) ? 0 : -1;
}
 
static int x11Dispatch(Platform *platform)
{
    X11 *x11 = (X11*)platform->implementation;
    if (xcb_connection_has_error(x11->connection)) {
        platform->running = false;
        x11Push(x11, (Event){ .kind = EVENT_QUIT });
        return -1;
    }
    xcb_generic_event_t *ge;
    while ((ge = xcb_poll_for_event(x11->connection))) {
        x11HandleEvent(x11, ge);
        free(ge);
    }
    return 0;
}
 
static int x11PollEvents(Platform *platform, int timeoutMilliseconds)
{
    X11 *x11 = (X11*)platform->implementation;
    xcb_flush(x11->connection);
    struct pollfd fd = {
        .fd = xcb_get_file_descriptor(x11->connection),
        .events = POLLIN,
    };
    int n = poll(&fd, 1, timeoutMilliseconds);
    if (n < 0 && errno != EINTR)
        return -1;
    return x11Dispatch(platform);
}
 
static int x11_create_vk_surface(Platform *platform, void *vulkanInstance, void *outSurface)
{
    X11 *x11 = (X11*)platform->implementation;
    VkXcbSurfaceCreateInfoKHR ci = {
        .sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR,
        .connection = x11->connection,
        .window = x11->window,
    };
    VkSurfaceKHR surface = VK_NULL_HANDLE;
    VkResult result = vkCreateXcbSurfaceKHR((VkInstance)vulkanInstance, &ci, NULL, &surface);
    if (result != VK_SUCCESS) {
        fprintf(stderr, "x11: vkCreateXcbSurfaceKHR failed (%d)\n", (int)result);
        return -1;
    }
    *(VkSurfaceKHR *)outSurface = surface;
    return 0;
}
 
static int x11_present(Platform *platform)
{
    X11 *x11 = (X11*)platform->implementation;
    if (platform->gpuPresent)
        return 0;
    if (!platform->pixels)
        return -1;
 
    if (x11->useShm) {
        xcb_shm_put_image(x11->connection, x11->window, x11->graphicsContext,
                          (uint16_t)platform->bufferWidth, (uint16_t)platform->bufferHeight,
                          0, 0, (uint16_t)platform->bufferWidth, (uint16_t)platform->bufferHeight,
                          0, 0, x11->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
                          0, x11->shmSegment, 0);
    } else {
        /* PutImage max request is limited; send in strips. */
        int max_rows = 16384 / (platform->bufferWidth * 4);
        if (max_rows < 1)
            max_rows = 1;
        for (int y = 0; y < platform->bufferHeight; y += max_rows) {
            int rows = platform->bufferHeight - y;
            if (rows > max_rows)
                rows = max_rows;
            xcb_put_image(x11->connection, XCB_IMAGE_FORMAT_Z_PIXMAP, x11->window, x11->graphicsContext,
                          (uint16_t)platform->bufferWidth, (uint16_t)rows, 0, (int16_t)y, 0,
                          x11->depth, (uint32_t)(platform->bufferWidth * rows * 4),
                          (const uint8_t *)(platform->pixels + y * platform->bufferWidth));
        }
    }
    xcb_flush(x11->connection);
    return 0;
}
 
static void x11_destroy(Platform *platform)
{
    X11 *x11 = (X11*)platform->implementation;
    if (!x11) return;
 
    x11FreeBuffer(x11);
    inputXkbFinish(&x11->xkb);
    if (x11->cursor)
        xcb_free_cursor(x11->connection, x11->cursor);
    if (x11->cursorContext)
        xcb_cursor_context_free(x11->cursorContext);
    if (x11->graphicsContext)
        xcb_free_gc(x11->connection, x11->graphicsContext);
    if (x11->window)
        xcb_destroy_window(x11->connection, x11->window);
    if (x11->connection)
        xcb_disconnect(x11->connection);
    free(x11);
    platform->implementation = NULL;
    platform->pixels = NULL;
}
 
int platformX11Open(Platform *platform, const char *title, int width, int height)
{
    X11 *x11 = (X11*)calloc(1, sizeof(*x11));
    if (!x11)
        return -1;
    x11->platform = platform;
    x11->shmFileDescriptor = -1;
    x11->shmId = -1;
    platform->implementation = x11;
    platform->backend = BACKEND_X11;
    platform->fileDescriptor = x11Fd;
    platform->flush = x11Flush;
    platform->dispatch = x11Dispatch;
    platform->pollEvents = x11PollEvents;
    platform->present = x11_present;
    platform->destroy = x11_destroy;
    platform->vulkanSurfaceExtension = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
    platform->createVulkanSurface = x11_create_vk_surface;
 
    int screen_n = 0;
    x11->connection = xcb_connect(NULL, &screen_n);
    if (!x11->connection || xcb_connection_has_error(x11->connection)) {
        fprintf(stderr, "x11: connect failed\n");
        x11_destroy(platform);
        return -1;
    }
 
    const xcb_setup_t *setup = xcb_get_setup(x11->connection);
    xcb_screen_iterator_t it = xcb_setup_roots_iterator(setup);
    for (int i = 0; i < screen_n; i++)
        xcb_screen_next(&it);
    x11->screen = it.data;
    x11->depth = x11->screen->root_depth;
 
    const xcb_query_extension_reply_t *shm_ext = xcb_get_extension_data(x11->connection, &xcb_shm_id);
    x11->useShm = shm_ext && shm_ext->present;
 
    uint32_t mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
    uint32_t values[2] = {
        x11->screen->black_pixel,
        XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_KEY_RELEASE |
        XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_BUTTON_MOTION |
        XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW |
        XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_EXPOSURE |
        XCB_EVENT_MASK_FOCUS_CHANGE,
    };
 
    x11->window = xcb_generate_id(x11->connection);
    xcb_create_window(x11->connection, XCB_COPY_FROM_PARENT, x11->window, x11->screen->root,
                      0, 0, (uint16_t)width, (uint16_t)height, 0,
                      XCB_WINDOW_CLASS_INPUT_OUTPUT, x11->screen->root_visual,
                      mask, values);
 
    x11->graphicsContext = xcb_generate_id(x11->connection);
    xcb_create_gc(x11->connection, x11->graphicsContext, x11->window, 0, NULL);
 
    x11->wmProtocols = intern_atom(x11->connection, "WM_PROTOCOLS");
    x11->wmDeleteWindow = intern_atom(x11->connection, "WM_DELETE_WINDOW");
    x11->netWmName = intern_atom(x11->connection, "_NET_WM_NAME");
    x11->utf8String = intern_atom(x11->connection, "UTF8_STRING");
    x11->netWmPid = intern_atom(x11->connection, "_NET_WM_PID");
 
    if (!title)
        title = "terminal";
    xcb_change_property(x11->connection, XCB_PROP_MODE_REPLACE, x11->window,
                        XCB_ATOM_WM_NAME, XCB_ATOM_STRING, 8,
                        (uint32_t)strlen(title), title);
    xcb_change_property(x11->connection, XCB_PROP_MODE_REPLACE, x11->window,
                        x11->netWmName, x11->utf8String, 8,
                        (uint32_t)strlen(title), title);
    xcb_icccm_set_wm_protocols(x11->connection, x11->window, x11->wmProtocols, 1, &x11->wmDeleteWindow);
    static const char wm_class[] = "terminal\0Terminal";
    xcb_icccm_set_wm_class(x11->connection, x11->window, sizeof(wm_class), wm_class);
 
    xcb_size_hints_t hints;
    memset(&hints, 0, sizeof(hints));
    xcb_icccm_size_hints_set_min_size(&hints, 160, 80);
    xcb_icccm_set_wm_normal_hints(x11->connection, x11->window, &hints);
 
    uint32_t pid = (uint32_t)getpid();
    xcb_change_property(x11->connection, XCB_PROP_MODE_REPLACE, x11->window,
                        x11->netWmPid, XCB_ATOM_CARDINAL, 32, 1, &pid);
 
    if (xcb_cursor_context_new(x11->connection, x11->screen, &x11->cursorContext) == 0) {
        x11->cursor = xcb_cursor_load_cursor(x11->cursorContext, "xterm");
        if (!x11->cursor)
            x11->cursor = xcb_cursor_load_cursor(x11->cursorContext, "left_ptr");
        if (x11->cursor) {
            uint32_t cid = x11->cursor;
            xcb_change_window_attributes(x11->connection, x11->window, XCB_CW_CURSOR, &cid);
        }
    }
 
    if (x11SetupXkb(x11) < 0) {
        x11_destroy(platform);
        return -1;
    }
    if (x11AllocBuffer(x11, width, height) < 0) {
        x11_destroy(platform);
        return -1;
    }
 
    xcb_map_window(x11->connection, x11->window);
    xcb_flush(x11->connection);
    platform->focused = true;
    return 0;
}
powered by btf.