Added a bit more involved example of Zig and Xlib

Author Mitja Felicijan <mitja.felicijan@gmail.com> 2024-09-17 08:48:40 +0200
Committer Mitja Felicijan <mitja.felicijan@gmail.com> 2024-09-17 08:48:40 +0200
Commit fadbf136de03215a9bfaca04ee336b4085589de4 (patch)
-rw-r--r-- README.md 1
-rw-r--r-- zig-x11-box/Makefile 2
-rw-r--r-- zig-x11-box/main.zig 103
3 files changed, 106 insertions, 0 deletions
diff --git a/README.md b/README.md
...
19
| [zig-telnet](./zig-telnet)       | Connects to Redis server like it is a basic telnet server.     |
19
| [zig-telnet](./zig-telnet)       | Connects to Redis server like it is a basic telnet server.     |
20
| [zig-x11](./zig-x11)             | Uses X11 to create a basic window without any bindings needed. |
20
| [zig-x11](./zig-x11)             | Uses X11 to create a basic window without any bindings needed. |
21
| [zig-http](./zig-http)           | Basic example of a HTTP 1.1 server without any routing etc.    |
21
| [zig-http](./zig-http)           | Basic example of a HTTP 1.1 server without any routing etc.    |
  
22
| [zig-x11-box](./zig-x11-box)     | Move a box around with arrow keys with Xlib and Zig.           |
diff --git a/zig-x11-box/Makefile b/zig-x11-box/Makefile
  
1
default:
  
2
	zig run main.zig -lX11 -lc
diff --git a/zig-x11-box/main.zig b/zig-x11-box/main.zig
  
1
// https://tronche.com/gui/x/xlib/
  
2
  
  
3
const std = @import("std");
  
4
const xlib = @cImport({
  
5
    @cInclude("X11/Xlib.h");
  
6
  
  
7
    // This should work and pull in header with all the mappings
  
8
    // making xlib.XK_Escape available but it doesn't.
  
9
    @cInclude("X11/keysymdef.h");
  
10
});
  
11
  
  
12
// Defining key symbols by hand from keysymdef.h file.
  
13
const KeySym = enum(u32) {
  
14
    ESCAPE = 0xFF1B,
  
15
    LEFT = 0xff51,
  
16
    UP = 0xff52,
  
17
    RIGHT = 0xff53,
  
18
    DOWN = 0xff54,
  
19
};
  
20
  
  
21
const Box = struct {
  
22
    x: i32,
  
23
    y: i32,
  
24
};
  
25
  
  
26
const StepSize = 30;
  
27
  
  
28
pub fn main() !void {
  
29
    const display = xlib.XOpenDisplay(null);
  
30
    if (display == null) {
  
31
        return error.DisplayOpenFailed;
  
32
    }
  
33
  
  
34
    const root_window = xlib.XDefaultRootWindow(display);
  
35
  
  
36
    const main_window = xlib.XCreateSimpleWindow(
  
37
        display,
  
38
        root_window,
  
39
        0,
  
40
        0,
  
41
        400,
  
42
        800,
  
43
        0,
  
44
        0,
  
45
        0xFFFFFF,
  
46
    );
  
47
  
  
48
    _ = xlib.XMapWindow(display, main_window);
  
49
    _ = xlib.XFlush(display);
  
50
  
  
51
    _ = xlib.XSelectInput(display, main_window, xlib.KeyPressMask);
  
52
    _ = xlib.XMapWindow(display, main_window);
  
53
  
  
54
    _ = xlib.XStoreName(display, main_window, "Moving boxes");
  
55
  
  
56
    var gc = xlib.XCreateGC(display, main_window, 0, null) orelse {
  
57
        std.debug.print("Failed to create graphics context\n", .{});
  
58
        return error.CreateGCFailed;
  
59
    };
  
60
    defer {
  
61
        _ = xlib.XFreeGC(display, gc);
  
62
    }
  
63
  
  
64
    var box = Box{ .x = 0, .y = 0 };
  
65
  
  
66
    var event: xlib.XEvent = undefined;
  
67
    while (true) {
  
68
        _ = xlib.XNextEvent(display, &event);
  
69
        if (event.type == xlib.KeyPress) {
  
70
            var keysym = xlib.XLookupKeysym(&event.xkey, 0);
  
71
  
  
72
            // NOTE: There probably is a better way of matching key presses
  
73
            //       without casting. I tried creating enum with type
  
74
            //       c_ulong without luck. More described in link below.
  
75
            //       https://ziglang.org/documentation/0.9.1/#Primitive-Types
  
76
  
  
77
            if (keysym == @intFromEnum(KeySym.ESCAPE)) {
  
78
                std.debug.print("Exiting game\n", .{});
  
79
                break;
  
80
            }
  
81
  
  
82
            if (keysym == @intFromEnum(KeySym.LEFT)) {
  
83
                box.x -= StepSize;
  
84
            }
  
85
  
  
86
            if (keysym == @intFromEnum(KeySym.RIGHT)) {
  
87
                box.x += StepSize;
  
88
            }
  
89
  
  
90
            if (keysym == @intFromEnum(KeySym.UP)) {
  
91
                box.y -= StepSize;
  
92
            }
  
93
  
  
94
            if (keysym == @intFromEnum(KeySym.DOWN)) {
  
95
                box.y += StepSize;
  
96
            }
  
97
        }
  
98
  
  
99
        _ = xlib.XClearWindow(display, main_window);
  
100
        _ = xlib.XDrawString(display, main_window, gc, 150, 150, "Use arrow keys.", 15);
  
101
        _ = xlib.XFillRectangle(display, main_window, gc, box.x, box.y, 100, 100);
  
102
    }
  
103
}