@Cloudef I confess that I struggle to understand the details of your platform, but your post made me want to talk about my somewhat related hobby project.
When time allows, I work on a linux x86_64 application framework that aims to realize a long-standing goal i have: distributing a graphical application as a single, fully dependency-free executable that works everywhere (on linux x86_64) and makes no compromises in using the user’s hardware. As such, this executable should be static, should not use libc, should not require the user to install any packages, and should still be able to use, for example, a GPU if available (without requiring one), and run without modification on X11 and Wayland. To achieve this, I rely on the custom dynamic library loader I started last year.
The final goal is a framework that provides many common utilities for applications or games, such as:
- windowing
- audio
- gamepads / tablets
- layout
- GUI components
- 2D and 3D graphics API abstractions
I have already achieved support for x11 and wayland, both with software rendering and egl + gles2, and with keyboard (including proper international support) and mouse handling.
Here is a screenshot of the same (static!) executable running in my x11 session and in the weston wayland compositor, using egl + gles2:
The associated code:
const std = @import("std");
pub const debug = struct {
pub const SelfInfo = dappfw.CustomSelfInfo;
};
const dappfw = @import("dappfw");
pub fn main(init: std.process.Init) !void {
const allocator = init.gpa;
const io = init.io;
try dappfw.init(allocator, io, init.minimal, .{ .app_name = "DAppFW Showcase" });
defer dappfw.deinit();
const window = try dappfw.createWindow(.{
.dm_type = .auto_prefer_wayland,
.r_type = .auto_prefer_egles2,
.title = "DAppFW Showcase",
.width = 800,
.height = 400,
.quit_on_close = true,
});
dappfw.showWindow(window);
const root_surface = dappfw.getWindowRootSurface(window);
while (!dappfw.shouldQuit()) {
// `true` here means "block until events are available"
try dappfw.collectEvents(.all, true);
if (dappfw.keyboardKeyPressed(window, .Q)) {
break;
}
// draw
try dappfw.clearSurface(root_surface, .black);
try dappfw.fillCircleOnSurface(
root_surface,
dappfw.getSurfaceCenter(root_surface).toFPoint(),
@floatFromInt(dappfw.getSurfaceMinDim(root_surface) / 12),
.red,
);
try dappfw.drawLineOnSurface(
root_surface,
.{ .x = @floatFromInt(dappfw.getSurfaceWidth(root_surface)), .y = 0 },
.{ .x = 0, .y = @floatFromInt(dappfw.getSurfaceHeight(root_surface)) },
.white,
);
if (dappfw.getWindowPointerPosition(window)) |pos| {
try dappfw.fillCircleOnSurface(
root_surface,
pos.toFPoint(),
10,
.blue,
);
}
// present
try dappfw.flush(.all);
}
}
Right now, the dynamic library loader is used to load these libraries on demand:
- libX11.so.6
- libXext.so.6
- libXi.so.6
- libxkbcommon.so.0
- libGLESv2.so.2
- libwayland-client.so.0
- libwayland-egl.so.1
- libwayland-cursor.so.0
- libwayland-server.so.0
- libEGL.so.1
…with many more to come. The only rule for a library to be eligible is its general availability in desktop environments. Other rules I want to enforce are:
- the same visuals and behavior, regardless of the selected backend
- full control over the application loop, with no callback registration (I might regret that later…)
- no bias toward immediate or retained mode for GUI
.dependencies = .{}in build.zig.zon- zig as the only language allowed to be compiled
The next step is audio. I will not lie, I am already behind where I expected to be at this point in the project.
