1

I am trying to write a simple window manager with xcb in zig where there is an event loop with some possible events (key press, ...). My system is running an arch linux and all the necessary libraries are installed. Here is my main.zig:

const std = @import("std");
const print = std.debug.print;
const xcb = @cImport({
    @cInclude("xcb/xcb.h");
});

pub fn main() !void {
    const conn: ?*xcb.xcb_connection_t = xcb.xcb_connect(null, null);
    defer xcb.xcb_disconnect(conn);

    if (conn == null or xcb.xcb_connection_has_error(conn) != 0) {
        print("Failed to connect to X server\n", .{});
        return error.XConnectionFailed;
    }

    const xcbsetup = xcb.xcb_get_setup(conn);
    if (xcbsetup == null) {
        print("Failed to get XCB setup\n", .{});
        return error.XCBSetupFailed;
    }

    const screen_iter = xcb.xcb_setup_roots_iterator(xcbsetup);
    if (screen_iter.rem == 0) {
        print("No screens found\n", .{});
        return error.NoScreens;
    }

    const screen: *xcb.xcb_screen_t = screen_iter.data;

    const win = xcb.xcb_generate_id(conn);
    // const event_mask = xcb.XCB_EVENT_MASK_KEY_PRESS;

    //  Event masks: capturing all possible events
    const event_mask = xcb.XCB_EVENT_MASK_EXPOSURE |
        xcb.XCB_EVENT_MASK_KEY_PRESS |
        xcb.XCB_EVENT_MASK_KEY_RELEASE |
        xcb.XCB_EVENT_MASK_BUTTON_PRESS |
        xcb.XCB_EVENT_MASK_BUTTON_RELEASE |
        xcb.XCB_EVENT_MASK_POINTER_MOTION |
        xcb.XCB_EVENT_MASK_ENTER_WINDOW |
        xcb.XCB_EVENT_MASK_LEAVE_WINDOW |
        xcb.XCB_EVENT_MASK_FOCUS_CHANGE |
        xcb.XCB_EVENT_MASK_STRUCTURE_NOTIFY;

    const value_list = [_]u32{event_mask};

    _ = xcb.xcb_create_window(
        conn,
        xcb.XCB_COPY_FROM_PARENT,
        win,
        screen.root,
        0,
        0, // x, y
        400,
        300, // width, height
        10, // border width
        xcb.XCB_WINDOW_CLASS_INPUT_OUTPUT,
        screen.root_visual,
        xcb.XCB_CW_EVENT_MASK,
        &value_list,
    );

    _ = xcb.xcb_map_window(conn, win);
    _ = xcb.xcb_flush(conn);

    while (true) {
        const event = xcb.xcb_wait_for_event(conn);
        if (event == null) {
            print("Error waiting for event\n", .{});
            continue;
        }

        switch (event.*.response_type) {
            xcb.XCB_KEY_PRESS => {
                const key_event: *xcb.xcb_key_press_event_t = @ptrCast(event);
                print("Key pressed: code = {}, state = {}\n", .{ key_event.detail, key_event.state });
            },
            else => {
                print("Unhandled event of type {}.\n", .{event.*.response_type});
            },
        }

        // Free the event
        // xcb.xcb_free_event(conn, event);
    }
}

Here is my build.zig:

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "blakewm",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    exe.linkSystemLibrary("xcb");
    b.installArtifact(exe);
}

I don't think there is a need to show my build.zig.zon since there is nothing special in it. Now there are two problems:

  1. I have no idea how one can free events in the event loop as in the c example they use free(ev).
  2. When I build the code with zig build and then run it with
Xephyr -ac -br -noreset -screen 800x600 :1 & sleep 1; DISPLAY=:1 ./zig-out/bin/blakewm

I see the following messages and cannot have it write all the keys being pressed:

The XKEYBOARD keymap compiler (xkbcomp) reports:
> Warning:          Could not resolve keysym XF86RefreshRateToggle
> Warning:          Could not resolve keysym XF86Accessibility
> Warning:          Could not resolve keysym XF86DoNotDisturb
Errors from xkbcomp are not fatal to the X server
Segmentation fault at address 0x0
???:?:?: 0x0 in ??? (???)
./runb.sh: line 1:  2898 Aborted                 (core dumped) DISPLAY=:1 ./zig-out/bin/blakewm

runb.sh just contains the Xephyr call so that I don't have to type it every time I want to test the code.

1 Answer 1

2

Apparently the free function is in the stdlib.h library and I just needed to add it to my c_imports like this:

const c = @cImport({
    @cInclude("xcb/xcb.h");
    @cInclude("stdlib.h");
});

Then, I changed all the xcb. to c. in the code and added c.free(event) at the end of the loop.

I ran zig build but there was a problem with compiler not finding free again. Finally, I understood that I have to add exe.linklibC(); to my build.zig so that it could work. It now runs and there is no major issue. There are only some warnings that I need to understand:

The XKEYBOARD keymap compiler (xkbcomp) reports:
> Warning:          Could not resolve keysym XF86RefreshRateToggle
> Warning:          Could not resolve keysym XF86Accessibility
> Warning:          Could not resolve keysym XF86DoNotDisturb
Errors from xkbcomp are not fatal to the X server
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.