- Zig 83.3%
- Objective-C 15.6%
- GLSL 1.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
`textureReadTarget` was the last stub. sokol has no readback and a target it created is GPU-private, so getBytes on it fails outright; the working route is a blit into a shared-storage staging texture, a wait, then getBytes from the copy. That is what dvui's Picture needs to export a PNG. It synchronises with the GPU, unavoidably — the pixels do not exist until the pass that writes them has run — so it belongs in export and debugging paths, not in a frame with a deadline. DVUI_SOKOL_DUMP_TARGETS=<prefix> writes every render target of one frame to raw RGBA files. That is what finally settled a blur nobody could see: the dumps showed the capture was a perfect image of the editor pane and the blur chain was working exactly as intended, which moved the question from "is it broken" to "is there anything in a blurred white page to look at". The dump holds its targets one extra frame on purpose. Nothing is on the GPU when `end()` returns — it records passes and `sg.commit()` runs later in the frame callback — so reading there returns uninitialised memory. The first version did, and every target came back a uniform magenta. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015nVTZMZW74ebw9bzNPcu2w |
||
| src | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| LICENSE | ||
| README.md | ||
dvui-sokol
Shared sokol backend for DVUI, used
by cue, quote, and wordandkey.
Modules
dvui_sokol— the DVUI backend itself (kind = .custom).runtime— small std-shim helpers (clock, getenv, fs, sleep, mutex) for code that does not want to threadstd.Iothrough every call.shader— generated GLSL → backend-specific shader bytecode (compiled bysokol-shdcat build time).
Consuming this package
In your build.zig.zon, declare both this package and dvui (matching the
pinned version below — Zig's package manager deduplicates by hash):
.dependencies = .{
.dvui_sokol = .{
.url = "git+https://git.urverk.org/urverk/dvui-sokol#<rev>",
.hash = "...",
},
.dvui = .{
.url = "git+https://github.com/david-vanderson/dvui#2459d676a26c11627593aad5e9ad4cbda42e2f1e",
.hash = "dvui-0.5.0-dev-AQFJmT4I3wAC_MQuAnjx7tZe7iRao6cN7E7vcdOlItYa",
},
},
In build.zig:
const ds_dep = b.dependency("dvui_sokol", .{ .target = target, .optimize = optimize });
const backend_mod = ds_dep.module("dvui_sokol");
const runtime_mod = ds_dep.module("runtime");
const dvui_dep = b.dependency("dvui", .{
.target = target,
.optimize = optimize,
.backend = .custom,
.libc = true,
.@"stb-image" = true,
});
const dvui_mod = dvui_dep.module("dvui");
@import("dvui").linkBackend(dvui_mod, backend_mod);
// Use dvui_mod and runtime_mod from your app modules.
In your main.zig:
const dvui = @import("dvui");
const sokol = @import("sokol");
const dvui_sokol = @import("dvui_sokol");
pub const dvui_app: dvui.App = .{
.config = .{ .startFn = &startOptions },
.frameFn = frame,
.initFn = init,
.deinitFn = deinit,
};
pub const main = dvui.App.main;
File-open handling (macOS)
The backend wires three file-delivery paths into a single per-frame drain so consumers don't have to think about which event a file arrived on:
- Window drag-and-drop — sokol's
FILES_DROPPEDevent. - Dock-icon drops / "Open With" — macOS's
application:openFiles:delegate method (legacy). - Terminal
open -a App -- fileand modernopenflows — macOS'sapplication:openURLs:delegate method.
The two delegate methods are installed at dyld static-init phase by
a tiny companion src/load_hook.m (a DvuiSokolDelegateGraft class
with a +load method). This timing is mandatory: macOS dispatches
the launch-time kAEOpenDocuments Apple Event before
applicationDidFinishLaunching: runs, so any later injection loses
the race and AppKit shows its "cannot open files in the X format"
fallback dialog. +load is the earliest hook the Obj-C runtime
exposes, and that's how this implementation wins.
In your frame loop, call drainDroppedFiles once per frame:
for (dvui_sokol.drainDroppedFiles()) |path| {
try editor.openFile(path);
}
Returned slices live in static buffers — valid until the next event of the same type replaces them, which in practice means valid for the rest of the current frame. Copy if you need to keep them.
CFBundleDocumentTypes in your Info.plist is not required —
open -a App is explicit about the target. (It is still useful if
you want Finder's "Open With…" menu to list your app, but it's
orthogonal to whether files actually open.)
Other macOS extras
- Press-and-hold suppression — macOS's accent-picker popup is disabled at startup so holding a printable key delivers repeated keyDown events (what text editors want). Same flag Terminal.app, VS Code, and Sublime set.
- Glass / blur compositing — opt-in via the
-Dglass=truebuild option. Off by default; consumers that don't render frosted popups pay zero overhead.
License
MIT