1// https://tronche.com/gui/x/xlib/
  2
  3const std = @import("std");
  4const 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.
 13const KeySym = enum(u32) {
 14    ESCAPE = 0xFF1B,
 15    LEFT = 0xff51,
 16    UP = 0xff52,
 17    RIGHT = 0xff53,
 18    DOWN = 0xff54,
 19};
 20
 21const Box = struct {
 22    x: i32,
 23    y: i32,
 24};
 25
 26const StepSize = 30;
 27
 28pub 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}