I am trying to write a window manager as my first big project in zig programming language. I am not looking for anything flashy right now. Here is my progress. This is indeed the first part. If I get to continue, there will be new posts following what I have done today.
Zig version: 0.13.0, on endevouros.
Installed packages: xcb, zig, zls(language server that I add to my neovim), xephyr, and some other necessary packages of Xorg.
I made the directory blakewm(blake will be the name of window manager, inspired by my favorite character in blake and mortimer cartoon), then, ran zig init
in blakewm directory to make necessary files.
Changed my build.zig to include xcb as you can see.
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);
}
Made a small code in my main.zig just to run a window.
const std = @import("std");
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) {
std.debug.print("Failed to connect to X server\n", .{});
return error.XConnectionFailed;
}
const screen: *xcb.xcb_screen_t = xcb.xcb_setup_roots_iterator(xcb.xcb_get_setup(conn)).data;
const win = xcb.xcb_generate_id(conn);
_ = 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,
0,
null,
);
_ = xcb.xcb_map_window(conn, win);
_ = xcb.xcb_flush(conn);
std.time.sleep(3 * std.time.ns_per_s); // Keep window open for 3 seconds
}
Ran zig build
in the directory to compile it. To run this with xephyr, I used this command:
Xephyr -ac -br -noreset -screen 800x600 :1 & sleep 1; DISPLAY=:1 ./zig-out/bin/blakewm
To run this easily, I created a file name runb.sh and put the command written above there. Gave it permission to run and now I can just use it whenever I want with ./runb.sh.
I do not know most of the things here(like what are they doing and what they are for), just used ai to create these lines and of course I had to fix some error since the version of zig the ai are trained with is older and so they produced lines of codes that would give error all the time.
To avoid copy pasting errors from my neovim terminal to clipboard, I made another file with executing permission that runs this line:
zig build 2>&1 | xclip -selection clipboard
Apparently this line puts the error in the log file of my build into clipboard (I got it from ai again).
The window was running with ./runb.sh and there was these messages:
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: 11217 Aborted (core dumped) DISPLAY=:1 ./zig-out/bin/blakewm
I am guessing that it is ok and for now things are working. Next, I will try to add a few more lines to add keypress listener so that i could print what i type into background of the window somehow. Please, let me know if you have any idea how to do this.
Top comments (1)
Oh I forgot to say that I used chatgpt and deepseek and grok in different places for help and error handling. but they all make a lot of mistakes since they only have access to the older version of zig.