Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@ jobs:
- name: Setup Zig
uses: marler8997/setup-anyzig@master

- name: Build
run: zig build --summary all install test-non-interactive
- name: Build 0.15.2
run: zig 0.15.2 build --summary all install test-non-interactive

- name: Build 0.16.0
run: zig 0.16.0 build --summary all install test-non-interactive
57 changes: 54 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const builtin = @import("builtin");
const std = @import("std");

const zig_atleast_16 = @import("builtin").zig_version.order(.{ .major = 0, .minor = 16, .patch = 0 }) != .lt;

/// Create the xtt (x11 true type) module with a custom TrueType module.
pub fn createXtt(b: *std.Build, zigx_dep: *std.Build.Dependency, TrueType: *std.Build.Module) *std.Build.Module {
return b.createModule(.{
Expand Down Expand Up @@ -38,11 +40,22 @@ pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

const zigversion_mod = b.createModule(.{
.root_source_file = if (zig_atleast_16) b.path("src/atleast16.zig") else b.path("src/before16.zig"),
});
// In almost all cases, Zig programs should only use this module, not the
// library defined below, that's for C programs.
const x_mod = b.addModule("x11", .{
.root_source_file = b.path("src/x.zig"),
.imports = &.{
.{ .name = "zigversion", .module = zigversion_mod },
},
});
if (!zig_atleast_16) {
if (b.lazyDependency("std16", .{})) |std16_dep| {
x_mod.addImport("std16", std16_dep.module("std16"));
}
}

const true_type_mod = b.dependency("TrueType", .{}).module("TrueType");
const xtt_mod = b.addModule("xtt", .{
Expand All @@ -62,6 +75,11 @@ pub fn build(b: *std.Build) void {
.single_threaded = true,
}),
});
if (!zig_atleast_16) {
if (b.lazyDependency("std16", .{})) |std16_dep| {
examples_exe.root_module.addImport("std16", std16_dep.module("std16"));
}
}
const run_examples = b.addRunArtifact(examples_exe);

const test_step = b.step("test", "Run all tests and interactive examples)");
Expand All @@ -80,6 +98,16 @@ pub fn build(b: *std.Build) void {
.{ .name = "x11", .module = x_mod },
},
});
if (!zig_atleast_16) {
if (b.lazyDependency("std16", .{})) |std16_dep| {
example_mod.addImport("std16", std16_dep.module("std16"));
}
} else {
if (b.lazyDependency("io", .{})) |io_dep| {
example_mod.addImport("Threaded", io_dep.module("Threaded"));
}
}

if (example.needs_text) {
example_mod.addImport("xtt", xtt_mod);

Expand All @@ -94,6 +122,13 @@ pub fn build(b: *std.Build) void {
.root_module = example_mod,
});

const enabled = switch (target.result.os.tag) {
// dbe example not working on 0.16 windows because it uses poll which seems
// to have broken on 0.16?
.windows => !std.mem.eql(u8, example.name, "dbe"),
else => true,
};

const exe_check = b.addExecutable(.{
.name = b.fmt("{s}_check", .{example.name}),
.root_module = example_mod,
Expand All @@ -102,11 +137,13 @@ pub fn build(b: *std.Build) void {

const install = b.addInstallArtifact(exe, .{});
build_examples_step.dependOn(&install.step);
b.getInstallStep().dependOn(&install.step);
if (enabled) b.getInstallStep().dependOn(&install.step);
b.step("build-" ++ example.name, "").dependOn(&install.step);

run_examples.addArtifactArg(exe);
run_examples.step.dependOn(&install.step);
if (enabled) {
run_examples.addArtifactArg(exe);
run_examples.step.dependOn(&install.step);
}

const run = b.addRunArtifact(exe);
run.step.dependOn(&install.step);
Expand Down Expand Up @@ -178,7 +215,16 @@ pub fn build(b: *std.Build) void {
const x_mod_with_target = b.createModule(.{
.root_source_file = b.path("src/x.zig"),
.target = target,
.imports = &.{
.{ .name = "zigversion", .module = zigversion_mod },
},
});
if (!zig_atleast_16) {
if (b.lazyDependency("std16", .{})) |std16_dep| {
x_mod_with_target.addImport("std16", std16_dep.module("std16"));
}
}

const unit_tests = b.addTest(.{
.root_module = x_mod_with_target,
});
Expand All @@ -199,6 +245,11 @@ pub fn build(b: *std.Build) void {
},
}),
});
if (!zig_atleast_16) {
if (b.lazyDependency("std16", .{})) |std16_dep| {
xauth_exe.root_module.addImport("std16", std16_dep.module("std16"));
}
}
const install = b.addInstallArtifact(xauth_exe, .{});
b.step("install-xauth", "").dependOn(&install.step);
test_non_interactive.dependOn(&install.step);
Expand Down
11 changes: 10 additions & 1 deletion build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@
.name = .x11,
.version = "0.0.0",
.fingerprint = 0x3220e772e6b06bc9,
.zig_version = "0.15.2",
.zig_version = "0.16.0",
.minimum_zig_version = "0.15.2",
.dependencies = .{
.std16 = .{
.path = "std16",
.lazy = true,
},
.io = .{
.url = "git+https://github.com/marler8997/zig-io#d9e63d8b17fb7567ff8c973d6dbea7e8391a465c",
.hash = "io-0.0.0-1IkbBbPlCwCDRE0r-SUWVvR4hUrcA5Rmln2KiKfQqXPN",
.lazy = true,
},
.TrueType = .{
.url = "git+https://codeberg.org/andrewrk/TrueType#b0f9867671a14ce4ed75a05a7e52c927623095e5",
.hash = "TrueType-0.0.0-Ne-mWMxxAQDit1oHfxlK2lkZAX8P7Wsa2SBPaR_xSpc8",
Expand Down
10 changes: 7 additions & 3 deletions examples/FrameTimeGraph.zig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const highlight_color = 0xcccccc;
const over_color = 0xcc3333;

font_dims: FontDims,
previous_time: ?std.time.Instant = null,
previous_time: ?std16.Io.Timestamp = null,
frame_times: [history_len]f32 = [1]f32{0} ** history_len,
cursor: u8 = 0,
max_ms: f32 = 50,
Expand All @@ -20,15 +20,16 @@ pub const FontDims = struct {

pub fn writeRender(
self: *FrameTimeGraph,
io: std16.Io,
sink: *x11.RequestSink,
drawable: x11.Drawable,
gc_id: x11.GraphicsContext,
window_width: u16,
window_height: u16,
) error{ WriteFailed, TextTooLong }!void {
const now = std.time.Instant.now() catch @panic("time not supported");
const now = std16.Io.Timestamp.now(io, .awake);
const elapsed_ms: f32 = if (self.previous_time) |prev|
@as(f32, @floatFromInt(now.since(prev))) / std.time.ns_per_ms
@as(f32, @floatFromInt(prev.durationTo(now).toMilliseconds()))
else
0;
self.previous_time = now;
Expand Down Expand Up @@ -129,5 +130,8 @@ pub fn writeRender(
self.cursor = (self.cursor + 1) % history_len;
}

const zig_atleast_16 = @import("builtin").zig_version.order(.{ .major = 0, .minor = 16, .patch = 0 }) != .lt;

const std = @import("std");
const std16 = if (zig_atleast_16) std else @import("std16");
const x11 = @import("x11");
72 changes: 44 additions & 28 deletions examples/dbe.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
const std = @import("std");
const x11 = @import("x11");

const zig_atleast_16 = @import("builtin").zig_version.order(.{ .major = 0, .minor = 16, .patch = 0 }) != .lt;
const std16 = if (zig_atleast_16) std else @import("std16");

const initial_window_width = 400;
const initial_window_height = 400;

Expand Down Expand Up @@ -43,22 +46,30 @@ const Root = struct {
depth: x11.Depth,
};

pub fn main() !void {
pub const main = if (zig_atleast_16) mainAtleast16 else mainBefore16;
fn mainAtleast16(init: std.process.Init.Minimal) !void {
var t: @import("Threaded") = .init_single_threaded;
try mainCompat(init.environ, t.io());
}
fn mainBefore16() !void {
try mainCompat(.{}, .legacy);
}
pub fn mainCompat(environ: std16.process.Environ, io: std16.Io) !void {
try x11.wsaStartup();

const stream: std.net.Stream, const ids: Ids, const keyrange: x11.KeycodeRange, const root: Root = blk: {
const socket: x11.Socket, const ids: Ids, const keyrange: x11.KeycodeRange, const root: Root = blk: {
var read_buffer: [1000]u8 = undefined;
var socket_reader, const used_auth = try x11.draft.connect(&read_buffer);
errdefer x11.disconnect(socket_reader.getStream());
var socket_reader, const used_auth = try x11.draft.connect(io, environ, &read_buffer);
errdefer x11.disconnect(io, socket_reader.socket);
_ = used_auth;
const setup = x11.readSetupSuccess(socket_reader.interface()) catch |err| switch (err) {
error.ReadFailed => return socket_reader.getError().?,
const setup = x11.readSetupSuccess(&socket_reader.interface) catch |err| switch (err) {
error.ReadFailed => return socket_reader.err.?,
error.EndOfStream, error.Protocol => |e| return e,
};
std.log.info("setup reply {f}", .{setup});
var source: x11.Source = .initFinishSetup(socket_reader.interface(), &setup);
var source: x11.Source = .initFinishSetup(&socket_reader.interface, &setup);
const screen = (x11.draft.readSetupDynamic(&source, &setup, .{}) catch |err| switch (err) {
error.ReadFailed => return socket_reader.getError().?,
error.ReadFailed => return socket_reader.err.?,
error.EndOfStream, error.Protocol => |e| return e,
}) orelse {
std.log.err("no screen?", .{});
Expand All @@ -70,7 +81,7 @@ pub fn main() !void {
std.process.exit(0xff);
}
break :blk .{
socket_reader.getStream(),
socket_reader.socket,
.{ .range = id_range },
try .init(setup.min_keycode, setup.max_keycode),
.{
Expand All @@ -83,26 +94,27 @@ pub fn main() !void {
},
};
};
defer x11.disconnect(stream);
defer x11.disconnect(io, socket);

var write_buffer: [1000]u8 = undefined;
var read_buffer: [1000]u8 = undefined;
var socket_writer = x11.socketWriter(stream, &write_buffer);
var socket_reader = x11.socketReader(stream, &read_buffer);
var socket_writer = x11.socketWriter(io, socket, &write_buffer);
var socket_reader = x11.socketReader(io, socket, &read_buffer);
var sink: x11.RequestSink = .{ .writer = &socket_writer.interface };
var source: x11.Source = .initAfterSetup(socket_reader.interface());
run(ids, &root, &sink, &socket_reader, &source, keyrange) catch |err| switch (err) {
var source: x11.Source = .initAfterSetup(&socket_reader.interface);
run(io, ids, &root, &sink, &socket_reader, &source, keyrange) catch |err| switch (err) {
error.WriteFailed => |e| return x11.onWriteError(e, socket_writer.err.?),
error.ReadFailed, error.EndOfStream, error.Protocol => |e| return source.onReadError(e, socket_reader.getError()),
error.ReadFailed, error.EndOfStream, error.Protocol => |e| return source.onReadError(e, socket_reader.err),
error.UnexpectedMessage => |e| return e,
};
}

fn run(
io: std16.Io,
ids: Ids,
root: *const Root,
sink: *x11.RequestSink,
socket_reader: *std.net.Stream.Reader,
socket_reader: *x11.SocketReader,
source: *x11.Source,
keyrange: x11.KeycodeRange,
) error{ WriteFailed, ReadFailed, EndOfStream, Protocol, UnexpectedMessage }!void {
Expand Down Expand Up @@ -166,15 +178,15 @@ fn run(

var window_width: u16 = initial_window_width;
var window_height: u16 = initial_window_height;
var animate: Animate = .{ .previous_time = std.time.Instant.now() catch @panic("monotonic timer unsupported") };
var animate: Animate = .{ .previous_time = std16.Io.Timestamp.now(io, .awake) };
var animate_frame_ms: i32 = 15;

while (true) {
try sink.writer.flush();

const action: enum { timeout, socket } = switch (pollSocketReader(socket_reader, 0)) {
.ready => .socket,
.timeout => if (getTimeout(animate.previous_time, animate_frame_ms)) |timeout_ms| switch (pollSocketReader(socket_reader, timeout_ms)) {
.timeout => if (getTimeout(io, animate.previous_time, animate_frame_ms)) |timeout_ms| switch (pollSocketReader(socket_reader, timeout_ms)) {
.ready => .socket,
.timeout => .timeout,
} else .timeout,
Expand All @@ -183,6 +195,7 @@ fn run(
switch (action) {
.timeout => {
try render(
io,
sink,
ids.window(),
ids.gc(),
Expand Down Expand Up @@ -241,6 +254,7 @@ fn run(
}
if (do_render) {
try render(
io,
sink,
ids.window(),
ids.gc(),
Expand All @@ -259,6 +273,7 @@ fn run(
const expose = try source.read2(.Expose);
std.log.info("{}", .{expose});
try render(
io,
sink,
ids.window(),
ids.gc(),
Expand Down Expand Up @@ -289,11 +304,11 @@ fn run(
}
}

fn pollSocketReader(socket_reader: *std.net.Stream.Reader, timeout_ms: i32) enum { ready, timeout } {
if (socket_reader.interface().bufferedLen() > 0) return .ready;
fn pollSocketReader(socket_reader: *x11.SocketReader, timeout_ms: i32) enum { ready, timeout } {
if (socket_reader.interface.bufferedLen() > 0) return .ready;
var poll_fds = [_]std.posix.pollfd{
.{
.fd = socket_reader.getStream().handle,
.fd = socket_reader.socket,
.events = std.posix.POLL.IN,
.revents = 0,
},
Expand All @@ -306,15 +321,15 @@ fn pollSocketReader(socket_reader: *std.net.Stream.Reader, timeout_ms: i32) enum
};
}

pub fn getTimeout(start: std.time.Instant, duration_ms: i32) ?u31 {
const now = std.time.Instant.now() catch @panic("monotonic timer unsupported");
const since_ms = @divTrunc(now.since(start), std.time.ns_per_ms);
pub fn getTimeout(io: std16.Io, start: std16.Io.Timestamp, duration_ms: i32) ?u31 {
const now = std16.Io.Timestamp.now(io, .awake);
const since_ms = start.durationTo(now).toMilliseconds();
if (since_ms >= duration_ms) return null;
return @intCast(duration_ms - @as(i32, @intCast(since_ms)));
}

const Animate = struct {
previous_time: std.time.Instant,
previous_time: std16.Io.Timestamp,
progress: f32 = 0,
};

Expand All @@ -336,6 +351,7 @@ const Dbe = union(enum) {
};

fn render(
io: std16.Io,
sink: *x11.RequestSink,
window: x11.Window,
gc_id: x11.GraphicsContext,
Expand All @@ -346,14 +362,14 @@ fn render(
window_height: u16,
) !void {
const elapsed_ms = blk: {
const now = std.time.Instant.now() catch @panic("monotonic timer unsupported");
const elapsed_ms = now.since(animate.previous_time);
const now = std16.Io.Timestamp.now(io, .awake);
const elapsed_ms = animate.previous_time.durationTo(now).toMilliseconds();
animate.previous_time = now;
break :blk elapsed_ms;
};

const animation_duration_ms: f32 = 2000.0; // 2 seconds for full cycle
const elapsed_ms_f32: f32 = @floatFromInt(elapsed_ms / std.time.ns_per_ms);
const elapsed_ms_f32: f32 = @floatFromInt(elapsed_ms);
const progress_increment: f32 = elapsed_ms_f32 / animation_duration_ms;
animate.progress = @mod(animate.progress + progress_increment, 1.0);

Expand Down
Loading
Loading