<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: S.Morteza Hosseini</title>
    <description>The latest articles on DEV Community by S.Morteza Hosseini (@mortimertz).</description>
    <link>https://dev.to/mortimertz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2911841%2F6c79c02e-a3dc-420a-bf8a-bc30220f9e47.jpg</url>
      <title>DEV Community: S.Morteza Hosseini</title>
      <link>https://dev.to/mortimertz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mortimertz"/>
    <language>en</language>
    <item>
      <title>Writing a window manager in zig with xcb - part 2</title>
      <dc:creator>S.Morteza Hosseini</dc:creator>
      <pubDate>Fri, 07 Mar 2025 10:28:10 +0000</pubDate>
      <link>https://dev.to/mortimertz/writing-a-window-manager-in-zig-with-xcb-part-2-50bn</link>
      <guid>https://dev.to/mortimertz/writing-a-window-manager-in-zig-with-xcb-part-2-50bn</guid>
      <description>&lt;p&gt;From the first post, I have been trying to understand how xcb library works and what are all those commands that was used previously. Today, I will explain how to get key press event in an event loop with xcb and zig.&lt;/p&gt;

&lt;p&gt;This time, let's try to go step by step and review the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const std = @import("std");
const print = std.debug.print;
const c = @cImport({
    @cInclude("xcb/xcb.h");
    @cInclude("stdlib.h");
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;importing standard library in Zig and assigning it to std,&lt;/li&gt;
&lt;li&gt;renaming the &lt;code&gt;std.debug.print&lt;/code&gt; function to &lt;code&gt;print&lt;/code&gt; for easier use,&lt;/li&gt;
&lt;li&gt;and importing two important C libraries. &lt;code&gt;stdlib.h&lt;/code&gt; has free function which is good to free event pointers at the end of each event loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, we start the main function as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub fn main() !void {
    const conn: ?*c.xcb_connection_t = c.xcb_connect(null, null);
    defer c.xcb_disconnect(conn);

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

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

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

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

    const win = c.xcb_generate_id(conn);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;xcb_connection&lt;/code&gt; establishes connection to the xorg server.&lt;/li&gt;
&lt;li&gt;The rest of the lines help us access our screen and generate a window in it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    //  Event masks: capturing all possible events
    const event_mask = c.XCB_EVENT_MASK_EXPOSURE |
        c.XCB_EVENT_MASK_KEY_PRESS |
        c.XCB_EVENT_MASK_KEY_RELEASE |
        c.XCB_EVENT_MASK_BUTTON_PRESS |
        c.XCB_EVENT_MASK_BUTTON_RELEASE |
        c.XCB_EVENT_MASK_POINTER_MOTION |
        c.XCB_EVENT_MASK_ENTER_WINDOW |
        c.XCB_EVENT_MASK_LEAVE_WINDOW |
        c.XCB_EVENT_MASK_FOCUS_CHANGE |
        c.XCB_EVENT_MASK_STRUCTURE_NOTIFY;

    const value_list = [_]u32{event_mask};

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

    _ = c.xcb_map_window(conn, win);
    _ = c.xcb_flush(conn);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We first define all the events that we are waiting for! &lt;code&gt;xcb&lt;/code&gt; library is not only to be used for window manager and it can be used by other applications as well. Those applications do not need to listen every even! We specify the events that we want by defining the event mask. Then we pass it to xcb to create a window for us.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This window is not automatically shown to users, so we have to use the map window function to show it. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, we use flush to send all the info to the xord server with our connection so that we can be ready to get events. apparently if we dont do this, we will receive those info instead of events (not completely understood it yet!).&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    while (true) {
        const event = c.xcb_wait_for_event(conn);
        defer c.free(event);

        if (event == null) {
            print("Error waiting for event\nBreaking from the event loop!\n", .{});
            break;
        }

        switch (event.*.response_type) {
            c.XCB_KEY_PRESS =&amp;gt; {
                const key_event: *c.xcb_key_press_event_t = @ptrCast(event);
                print("Key pressed: code = {}, state = {}\n", .{ key_event.detail, key_event.state });
            },
            else =&amp;gt; {
                print("Unhandled event of type {}.\n", .{event.*.response_type});
            },
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is our event loop at the end of the main function. event is a pointer to struct type and in C we get its field by &lt;code&gt;event-&amp;gt;response_type&lt;/code&gt;. In Zig this is done by &lt;code&gt;.*&lt;/code&gt; instead of &lt;code&gt;-&amp;gt;&lt;/code&gt;. In our switch we first check what is the type of the event passed to us and then just type cast it to the corresponding type by &lt;code&gt;@ptrCast()&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now that this is done, we just have to add &lt;code&gt;exe.linklibC();&lt;/code&gt; in our &lt;code&gt;build.zig&lt;/code&gt; file so that our compiler links libc when compiling this code and we are good to go. Here is our &lt;code&gt;build.zig&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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");
    exe.linkLibC();
    b.installArtifact(exe);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As usual, I built this code with &lt;code&gt;zig build&lt;/code&gt; and ran it using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Xephyr -ac -br -noreset -screen 800x600 :1 &amp;amp; sleep 1; DISPLAY=:1 ./zig-out/bin/blakewm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some references to learn &lt;code&gt;xcb&lt;/code&gt;, &lt;code&gt;Zig&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.x.org/archive/X11R7.5/doc/libxcb/tutorial/index.html" rel="noopener noreferrer"&gt;Basic Graphics Programming With The XCB Library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://zig.guide" rel="noopener noreferrer"&gt;Zig guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>zig</category>
      <category>windowmanager</category>
      <category>xcb</category>
      <category>programming</category>
    </item>
    <item>
      <title>Writing a window manager in zig with xcb - part 1</title>
      <dc:creator>S.Morteza Hosseini</dc:creator>
      <pubDate>Wed, 05 Mar 2025 10:49:06 +0000</pubDate>
      <link>https://dev.to/mortimertz/writing-a-window-manager-in-zig-with-xcb-4ife</link>
      <guid>https://dev.to/mortimertz/writing-a-window-manager-in-zig-with-xcb-4ife</guid>
      <description>&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;Zig version: 0.13.0, on endevouros. &lt;br&gt;
Installed packages: xcb, zig, zls(language server that I add to my neovim), xephyr, and some other necessary packages of Xorg.&lt;/p&gt;

&lt;p&gt;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 &lt;code&gt;zig init&lt;/code&gt; in blakewm directory to make necessary files. &lt;/p&gt;

&lt;p&gt;Changed my build.zig to include xcb as you can see.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 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);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Made a small code in my main.zig just to run a window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;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
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ran &lt;code&gt;zig build&lt;/code&gt; in the directory to compile it. To run this with xephyr, I used this command: &lt;br&gt;
&lt;code&gt;Xephyr -ac -br -noreset -screen 800x600 :1 &amp;amp; sleep 1; DISPLAY=:1 ./zig-out/bin/blakewm&lt;/code&gt;&lt;br&gt;
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.&lt;/p&gt;

&lt;p&gt;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. &lt;/p&gt;

&lt;p&gt;To avoid copy pasting errors from my neovim terminal to clipboard, I made another file with executing permission that runs this line:&lt;br&gt;
&lt;code&gt;zig build 2&amp;gt;&amp;amp;1 | xclip -selection clipboard&lt;/code&gt;&lt;br&gt;
Apparently this line puts the error in the log file of my build into clipboard (I got it from ai again). &lt;/p&gt;

&lt;p&gt;The window was running with ./runb.sh and there was these messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The XKEYBOARD keymap compiler (xkbcomp) reports:
&amp;gt; Warning:          Could not resolve keysym XF86RefreshRateToggle
&amp;gt; Warning:          Could not resolve keysym XF86Accessibility
&amp;gt; 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

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

</description>
      <category>zig</category>
      <category>programming</category>
      <category>xcb</category>
      <category>windowmanager</category>
    </item>
  </channel>
</rss>
