windows implementation
This commit is contained in:
parent
0c8270fbef
commit
d1c4f14877
22
README.md
22
README.md
|
|
@ -1,20 +1,25 @@
|
||||||
# Uhdk
|
# Uhdk
|
||||||
|
|
||||||
A small macOS desktop platform library written in Zig 0.16.0 with a C99 ABI.
|
A small desktop platform library written in Zig 0.16.0 with a C99 ABI.
|
||||||
It provides windows, input and IME, clipboard, file dialogs, drag and drop, menus,
|
It provides windows, input and IME, clipboard, file dialogs, drag and drop, menus,
|
||||||
async file operations, file watching, and OpenGL context creation. The macOS
|
async file operations, file watching, and OpenGL context creation. The macOS
|
||||||
backend uses AppKit, OpenGL, and FSEvents through a private Objective-C bridge.
|
backend uses AppKit, OpenGL, and FSEvents through a private Objective-C bridge.
|
||||||
|
|
||||||
This directory is a standalone source package. It does not depend on the parent
|
This directory is a standalone source package. It does not depend on the parent
|
||||||
repository, its examples, fonts, skills, or development tools. Currently macOS is
|
repository, its examples, fonts, skills, or development tools. macOS builds require
|
||||||
the only implemented backend. Building requires Xcode Command Line Tools.
|
Xcode Command Line Tools. The Windows Win32/WGL backend cross-compiles for
|
||||||
|
`x86_64-windows-gnu`; runtime verification on Windows is pending. It requires
|
||||||
|
Windows 10 version 1703 or later and an OpenGL 3.3-capable driver.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
zig build # zig-out/lib/libuhdk.a and zig-out/include/
|
zig build # zig-out/lib/libuhdk.a and zig-out/include/
|
||||||
zig build -Dshared=true # zig-out/lib/libuhdk.dylib and headers
|
zig build -Dshared=true # zig-out/lib/libuhdk.dylib and headers
|
||||||
zig build test # core library tests
|
zig build test # run core library tests on the native target
|
||||||
|
zig build -Dtarget=x86_64-windows-gnu
|
||||||
|
zig build -Dtarget=x86_64-windows-gnu -Dshared=true
|
||||||
|
zig build check -Dtarget=x86_64-windows-gnu # compile only
|
||||||
```
|
```
|
||||||
|
|
||||||
## Use from Zig
|
## Use from Zig
|
||||||
|
|
@ -63,3 +68,12 @@ The library includes the GLAD loader implementation. With a current context insi
|
||||||
`uhdk_gl_context_get_proc`. Keep a `GladGLContext` per native context; its members
|
`uhdk_gl_context_get_proc`. Keep a `GladGLContext` per native context; its members
|
||||||
are named `Clear`, `DrawArrays`, etc. Check `VERSION_3_3` after loading. Do not define
|
are named `Clear`, `DrawArrays`, etc. Check `VERSION_3_3` after loading. Do not define
|
||||||
`GLAD_GL_IMPLEMENTATION` in your application when linking libuhdk.
|
`GLAD_GL_IMPLEMENTATION` in your application when linking libuhdk.
|
||||||
|
|
||||||
|
On Windows, the static artifact is `zig-out/lib/uhdk.lib`; shared builds install
|
||||||
|
`zig-out/bin/uhdk.dll` and its import library under `zig-out/lib/`. Keep the DLL
|
||||||
|
beside your executable. The first lifecycle caller establishes the Windows
|
||||||
|
platform thread; its message loop also owns COM dialogs, menus, clipboard and
|
||||||
|
watch completion. Input uses IMM32 composition; TSF reconversion and pen/touch
|
||||||
|
are not implemented. Native UTF-16 path bytes are kept separately from the WTF-8
|
||||||
|
paths passed to Zig I/O. If a native path cannot be exported losslessly as a shell
|
||||||
|
URI, URI export returns `UNSUPPORTED`; native-path export still preserves it.
|
||||||
|
|
|
||||||
37
build.zig
37
build.zig
|
|
@ -2,7 +2,7 @@ const std = @import("std");
|
||||||
|
|
||||||
pub fn build(b: *std.Build) void {
|
pub fn build(b: *std.Build) void {
|
||||||
const target = b.standardTargetOptions(.{});
|
const target = b.standardTargetOptions(.{});
|
||||||
if (target.result.os.tag != .macos) @panic("Uhdk currently implements macOS only.");
|
if (target.result.os.tag != .macos and target.result.os.tag != .windows) @panic("Uhdk supports macOS and Windows.");
|
||||||
const optimize = b.standardOptimizeOption(.{});
|
const optimize = b.standardOptimizeOption(.{});
|
||||||
const shared = b.option(bool, "shared", "Build libuhdk as a shared library instead of static") orelse false;
|
const shared = b.option(bool, "shared", "Build libuhdk as a shared library instead of static") orelse false;
|
||||||
const module = b.createModule(.{
|
const module = b.createModule(.{
|
||||||
|
|
@ -12,25 +12,30 @@ pub fn build(b: *std.Build) void {
|
||||||
.link_libc = true,
|
.link_libc = true,
|
||||||
});
|
});
|
||||||
const native = b.addTranslateC(.{
|
const native = b.addTranslateC(.{
|
||||||
.root_source_file = b.path("src/macos/native.h"),
|
.root_source_file = b.path("src/native.h"),
|
||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
native.addIncludePath(b.path("include"));
|
native.addIncludePath(b.path("include"));
|
||||||
module.addImport("native", native.createModule());
|
module.addImport("native", native.createModule());
|
||||||
module.addIncludePath(b.path("include"));
|
module.addIncludePath(b.path("include"));
|
||||||
module.addIncludePath(b.path("src/macos"));
|
module.addIncludePath(b.path("src"));
|
||||||
module.addCSourceFile(.{
|
if (target.result.os.tag == .macos) {
|
||||||
.file = b.path("src/macos/native.m"),
|
module.addCSourceFile(.{
|
||||||
.flags = &.{
|
.file = b.path("src/macos/native.m"),
|
||||||
"-fobjc-arc", "-fblocks", "-Wno-deprecated-declarations",
|
.flags = &.{
|
||||||
"-Wall", "-Wextra", "-Werror",
|
"-fobjc-arc", "-fblocks", "-Wno-deprecated-declarations",
|
||||||
},
|
"-Wall", "-Wextra", "-Werror",
|
||||||
});
|
},
|
||||||
module.addCSourceFile(.{ .file = b.path("src/glad.c"), .flags = &.{"-std=c99"} });
|
});
|
||||||
module.linkFramework("Cocoa", .{});
|
module.linkFramework("Cocoa", .{});
|
||||||
module.linkFramework("OpenGL", .{});
|
module.linkFramework("OpenGL", .{});
|
||||||
module.linkFramework("CoreServices", .{});
|
module.linkFramework("CoreServices", .{});
|
||||||
|
} else {
|
||||||
|
module.addCSourceFile(.{ .file = b.path("src/windows/native.c"), .flags = &.{ "-std=c11", "-Wall", "-Wextra", "-Werror", "-DUNICODE", "-D_UNICODE" } });
|
||||||
|
for ([_][]const u8{ "user32", "gdi32", "opengl32", "shell32", "ole32", "uuid", "imm32", "comctl32", "shlwapi", "advapi32" }) |name| module.linkSystemLibrary(name, .{});
|
||||||
|
}
|
||||||
|
module.addCSourceFile(.{ .file = b.path("src/glad.c"), .flags = if (shared) &.{ "-std=c99", "-DGLAD_API_CALL_EXPORT", "-DGLAD_API_CALL_EXPORT_BUILD" } else &.{"-std=c99"} });
|
||||||
const lib = b.addLibrary(.{
|
const lib = b.addLibrary(.{
|
||||||
.name = "uhdk",
|
.name = "uhdk",
|
||||||
.linkage = if (shared) .dynamic else .static,
|
.linkage = if (shared) .dynamic else .static,
|
||||||
|
|
@ -48,6 +53,9 @@ pub fn build(b: *std.Build) void {
|
||||||
b.getInstallStep().dependOn(&install_lib.step);
|
b.getInstallStep().dependOn(&install_lib.step);
|
||||||
b.getInstallStep().dependOn(&install_headers.step);
|
b.getInstallStep().dependOn(&install_headers.step);
|
||||||
const unit = b.addTest(.{ .root_module = module });
|
const unit = b.addTest(.{ .root_module = module });
|
||||||
|
const check_step = b.step("check", "Compile library and core tests without running them");
|
||||||
|
check_step.dependOn(&lib.step);
|
||||||
|
check_step.dependOn(&unit.step);
|
||||||
const unit_run = b.addRunArtifact(unit);
|
const unit_run = b.addRunArtifact(unit);
|
||||||
b.step("test", "Run core library tests").dependOn(&unit_run.step);
|
b.step("test", "Run core library tests").dependOn(&unit_run.step);
|
||||||
const public_c = b.addTranslateC(.{
|
const public_c = b.addTranslateC(.{
|
||||||
|
|
@ -56,6 +64,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
public_c.addIncludePath(b.path("include"));
|
public_c.addIncludePath(b.path("include"));
|
||||||
|
if (shared) public_c.defineCMacro("UHDK_SHARED", "1");
|
||||||
const public_module = b.addModule("uhdk", .{
|
const public_module = b.addModule("uhdk", .{
|
||||||
.root_source_file = public_c.getOutput(),
|
.root_source_file = public_c.getOutput(),
|
||||||
.target = target,
|
.target = target,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#define UHDK_H_INCLUDED
|
#define UHDK_H_INCLUDED
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Uhdk desktop platform API — v0.1, macOS backend.
|
* Uhdk desktop platform API — v0.1, macOS and Windows backends.
|
||||||
*
|
*
|
||||||
* Implementation: Zig. ABI: C. Header baseline: C99 (also usable from C++).
|
* Implementation: Zig. ABI: C. Header baseline: C99 (also usable from C++).
|
||||||
* No libc runtime objects or allocation contract.
|
* No libc runtime objects or allocation contract.
|
||||||
|
|
@ -484,7 +484,10 @@ UHDK_API uhdk_status UHDK_CALL uhdk_window_cancel_composition_async(uhdk_window
|
||||||
/* File references preserve native names, including non-UTF-8 POSIX paths.
|
/* File references preserve native names, including non-UTF-8 POSIX paths.
|
||||||
* Display names are UTF-8. URI/native-path export is explicit and owned by the
|
* Display names are UTF-8. URI/native-path export is explicit and owned by the
|
||||||
* caller's buffer. Windows native path bytes are UTF-16LE (no terminator),
|
* caller's buffer. Windows native path bytes are UTF-16LE (no terminator),
|
||||||
* POSIX native paths are uninterpreted bytes. A reference can carry an access
|
* POSIX native paths are uninterpreted bytes. Windows URI export returns
|
||||||
|
* UNSUPPORTED when the shell cannot represent a native name losslessly (such
|
||||||
|
* as unpaired UTF-16 surrogates); native-path export remains available.
|
||||||
|
* A reference can carry an access
|
||||||
* grant; retaining it keeps that grant alive where the OS permits. Persistence
|
* grant; retaining it keeps that grant alive where the OS permits. Persistence
|
||||||
* across launches/bookmark serialization is deferred to a future extension.
|
* across launches/bookmark serialization is deferred to a future extension.
|
||||||
* Buffer queries: NULL/0 gets required byte count in out_len and returns UHDK_STATUS_OK.
|
* Buffer queries: NULL/0 gets required byte count in out_len and returns UHDK_STATUS_OK.
|
||||||
|
|
@ -523,9 +526,11 @@ typedef struct uhdk_file_info {
|
||||||
* Read/write accept regular files only; final-component symlinks are rejected.
|
* Read/write accept regular files only; final-component symlinks are rejected.
|
||||||
* Write copies bytes at submission, stages an exclusive same-directory temp,
|
* Write copies bytes at submission, stages an exclusive same-directory temp,
|
||||||
* preserves POSIX mode of an existing regular file, then renames atomically.
|
* preserves POSIX mode of an existing regular file, then renames atomically.
|
||||||
|
* Windows rejects read-only destinations; replacement gets the directory's
|
||||||
|
* inherited permissions and does not preserve other destination attributes.
|
||||||
* Symlinks/nonregular destinations are rejected. ACLs/xattrs/ownership are not
|
* Symlinks/nonregular destinations are rejected. ACLs/xattrs/ownership are not
|
||||||
* preserved; replacement requires a directory writable by the current user.
|
* preserved; replacement requires a directory writable by the current user.
|
||||||
* New files use mode 0600. No power-loss durability or conflict detection promise.
|
* New POSIX files use mode 0600. No power-loss durability or conflict detection promise.
|
||||||
* No silent truncate fallback. Cancellation before rename leaves the target intact.
|
* No silent truncate fallback. Cancellation before rename leaves the target intact.
|
||||||
*/
|
*/
|
||||||
UHDK_API uhdk_status UHDK_CALL uhdk_file_read_all_async(uhdk_file *, uint64_t max_bytes,
|
UHDK_API uhdk_status UHDK_CALL uhdk_file_read_all_async(uhdk_file *, uint64_t max_bytes,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,9 @@
|
||||||
* uhdk_gl_context_get_proc, inside a begin_frame/end_frame bracket. Keep one
|
* uhdk_gl_context_get_proc, inside a begin_frame/end_frame bracket. Keep one
|
||||||
* table per context and use it only while that context is current.
|
* table per context and use it only while that context is current.
|
||||||
*/
|
*/
|
||||||
|
#if defined(UHDK_SHARED)
|
||||||
|
#define GLAD_API_CALL_EXPORT
|
||||||
|
#endif
|
||||||
#include "glad/gl.h"
|
#include "glad/gl.h"
|
||||||
|
|
||||||
#endif /* UHDK_OPENGL_H_INCLUDED */
|
#endif /* UHDK_OPENGL_H_INCLUDED */
|
||||||
|
|
|
||||||
|
|
@ -73,17 +73,19 @@ pub fn step(self: *FileOperation) !Result {
|
||||||
};
|
};
|
||||||
if (stat) |existing| {
|
if (stat) |existing| {
|
||||||
if (existing.kind != .file) return error.NotRegularFile;
|
if (existing.kind != .file) return error.NotRegularFile;
|
||||||
|
if (@import("builtin").os.tag == .windows and existing.permissions.toAttributes().READONLY)
|
||||||
|
return error.AccessDenied;
|
||||||
}
|
}
|
||||||
self.atomic_file = try cwd.createFileAtomic(self.io, self.path, .{
|
self.atomic_file = try cwd.createFileAtomic(self.io, self.path, .{
|
||||||
.permissions = .fromMode(0o600),
|
.permissions = if (@import("builtin").os.tag == .windows) .default_file else .fromMode(0o600),
|
||||||
.replace = true,
|
.replace = true,
|
||||||
});
|
});
|
||||||
if (stat) |existing| {
|
if (@import("builtin").os.tag != .windows) if (stat) |existing| {
|
||||||
try self.atomic_file.?.file.setPermissions(
|
try self.atomic_file.?.file.setPermissions(
|
||||||
self.io,
|
self.io,
|
||||||
.fromMode(existing.permissions.toMode() & 0o777),
|
.fromMode(existing.permissions.toMode() & 0o777),
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
.info => unreachable,
|
.info => unreachable,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ pub const Gl = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const File = struct {
|
pub const File = struct {
|
||||||
|
native_path: []const u8 = &.{},
|
||||||
path: [:0]const u8 = "",
|
path: [:0]const u8 = "",
|
||||||
uri: []const u8 = "",
|
uri: []const u8 = "",
|
||||||
display: []const u8 = "",
|
display: []const u8 = "",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
//! C ABI entry points for app.
|
//! C ABI entry points for app.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const backend_kind = if (@import("builtin").os.tag == .windows) c.UHDK_BACKEND_WINDOWS else c.UHDK_BACKEND_MACOS;
|
||||||
const c = @import("native");
|
const c = @import("native");
|
||||||
const runtime = @import("../runtime.zig");
|
const runtime = @import("../runtime.zig");
|
||||||
const abi = @import("../abi.zig");
|
const abi = @import("../abi.zig");
|
||||||
|
|
@ -19,7 +20,7 @@ pub export fn uhdk_app_create(desc: [*c]const c.uhdk_app_desc, out: [*c]?*c.uhdk
|
||||||
desc.*.reserved != 0 or
|
desc.*.reserved != 0 or
|
||||||
!abi.validText(desc.*.display_name, true) or
|
!abi.validText(desc.*.display_name, true) or
|
||||||
!abi.validText(desc.*.application_id, true)) return abi.INVALID;
|
!abi.validText(desc.*.application_id, true)) return abi.INVALID;
|
||||||
if (desc.*.preferred_backend != c.UHDK_BACKEND_AUTO and desc.*.preferred_backend != c.UHDK_BACKEND_MACOS) return c.UHDK_STATUS_UNSUPPORTED;
|
if (desc.*.preferred_backend != c.UHDK_BACKEND_AUTO and desc.*.preferred_backend != backend_kind) return c.UHDK_STATUS_UNSUPPORTED;
|
||||||
if (singleton) return c.UHDK_STATUS_BUSY;
|
if (singleton) return c.UHDK_STATUS_BUSY;
|
||||||
const gpa = std.heap.smp_allocator;
|
const gpa = std.heap.smp_allocator;
|
||||||
const backend = gpa.create(std.Io.Threaded) catch return abi.OOM;
|
const backend = gpa.create(std.Io.Threaded) catch return abi.OOM;
|
||||||
|
|
@ -218,7 +219,7 @@ pub export fn uhdk_app_set_wake_deadline(handle: ?*c.uhdk_app, deadline: u64) ab
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn uhdk_app_get_backend(_: ?*c.uhdk_app) c.uhdk_backend {
|
pub export fn uhdk_app_get_backend(_: ?*c.uhdk_app) c.uhdk_backend {
|
||||||
return c.UHDK_BACKEND_MACOS;
|
return backend_kind;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub export fn uhdk_app_has_capability(_: ?*c.uhdk_app, cap: c.uhdk_capability) c.uhdk_bool {
|
pub export fn uhdk_app_has_capability(_: ?*c.uhdk_app, cap: c.uhdk_capability) c.uhdk_bool {
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ pub export fn uhdk_file_create_from_native_path(
|
||||||
if (handle == null or
|
if (handle == null or
|
||||||
out == null or
|
out == null or
|
||||||
!abi.validSpan(path.ptr, path.len) or
|
!abi.validSpan(path.ptr, path.len) or
|
||||||
path.len == 0 or
|
path.len == 0) return abi.INVALID;
|
||||||
abi.bytes(path)[0] != '/' or
|
if (@import("builtin").os.tag != .windows and
|
||||||
std.mem.findScalar(u8, abi.bytes(path), 0) != null) return abi.INVALID;
|
(abi.bytes(path)[0] != '/' or std.mem.findScalar(u8, abi.bytes(path), 0) != null)) return abi.INVALID;
|
||||||
if (runtime.checkThread(runtime.fromAppHandle(handle)) != abi.OK) return c.UHDK_STATUS_WRONG_THREAD;
|
if (runtime.checkThread(runtime.fromAppHandle(handle)) != abi.OK) return c.UHDK_STATUS_WRONG_THREAD;
|
||||||
const object = runtime.createObject(runtime.fromAppHandle(handle), c.Z_KIND_FILE) catch return abi.OOM;
|
const object = runtime.createObject(runtime.fromAppHandle(handle), c.Z_KIND_FILE) catch return abi.OOM;
|
||||||
const status = c.z_native_file_init(runtime.castHandle(*c.uhdk_file, object), path, .{ .ptr = null, .len = 0 }, null);
|
const status = c.z_native_file_init(runtime.castHandle(*c.uhdk_file, object), path, .{ .ptr = null, .len = 0 }, null);
|
||||||
|
|
@ -91,9 +91,11 @@ pub export fn uhdk_file_copy_representation(
|
||||||
const data = switch (form) {
|
const data = switch (form) {
|
||||||
c.UHDK_FILE_DISPLAY_NAME => object.payload.file.display,
|
c.UHDK_FILE_DISPLAY_NAME => object.payload.file.display,
|
||||||
c.UHDK_FILE_URI => object.payload.file.uri,
|
c.UHDK_FILE_URI => object.payload.file.uri,
|
||||||
c.UHDK_FILE_NATIVE_PATH => object.payload.file.path,
|
c.UHDK_FILE_NATIVE_PATH => object.payload.file.native_path,
|
||||||
else => return abi.INVALID,
|
else => return abi.INVALID,
|
||||||
};
|
};
|
||||||
|
if (@import("builtin").os.tag == .windows and form == c.UHDK_FILE_URI and data.len == 0)
|
||||||
|
return c.UHDK_STATUS_UNSUPPORTED;
|
||||||
out.* = data.len;
|
out.* = data.len;
|
||||||
if (buffer == null and capacity == 0) return abi.OK;
|
if (buffer == null and capacity == 0) return abi.OK;
|
||||||
if (capacity < data.len) return c.UHDK_STATUS_BUFFER_TOO_SMALL;
|
if (capacity < data.len) return c.UHDK_STATUS_BUFFER_TOO_SMALL;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
//! C ABI entry points for callbacks.
|
//! C ABI entry points for callbacks.
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const c = @import("native");
|
const c = @import("native");
|
||||||
const abi = @import("../abi.zig");
|
const abi = @import("abi.zig");
|
||||||
const runtime = @import("../runtime.zig");
|
const runtime = @import("runtime.zig");
|
||||||
|
|
||||||
export fn z_emit(handle: ?*c.uhdk_app, event: [*c]const c.uhdk_event) void {
|
export fn z_emit(handle: ?*c.uhdk_app, event: [*c]const c.uhdk_event) void {
|
||||||
runtime.emit(handle, event);
|
runtime.emit(handle, event);
|
||||||
|
|
@ -65,7 +65,15 @@ export fn z_file_init(
|
||||||
) abi.Status {
|
) abi.Status {
|
||||||
const object = runtime.fromObjectHandle(handle);
|
const object = runtime.fromObjectHandle(handle);
|
||||||
const arena = object.arena.allocator();
|
const arena = object.arena.allocator();
|
||||||
object.payload.file.path = arena.dupeZ(u8, abi.bytes(path)) catch return abi.OOM;
|
object.payload.file.native_path = arena.dupe(u8, abi.bytes(path)) catch return abi.OOM;
|
||||||
|
if (@import("builtin").os.tag == .windows) {
|
||||||
|
if (path.len % 2 != 0) return abi.INVALID;
|
||||||
|
const wide = arena.alloc(u16, @intCast(path.len / 2)) catch return abi.OOM;
|
||||||
|
@memcpy(std.mem.sliceAsBytes(wide), abi.bytes(path));
|
||||||
|
object.payload.file.path = std.unicode.wtf16LeToWtf8AllocZ(arena, wide) catch return abi.OOM;
|
||||||
|
} else {
|
||||||
|
object.payload.file.path = arena.dupeZ(u8, abi.bytes(path)) catch return abi.OOM;
|
||||||
|
}
|
||||||
object.payload.file.uri = arena.dupe(u8, abi.textBytes(uri)) catch return abi.OOM;
|
object.payload.file.uri = arena.dupe(u8, abi.textBytes(uri)) catch return abi.OOM;
|
||||||
object.payload.file.display = arena.dupe(u8, abi.textBytes(display)) catch return abi.OOM;
|
object.payload.file.display = arena.dupe(u8, abi.textBytes(display)) catch return abi.OOM;
|
||||||
object.native = grant;
|
object.native = grant;
|
||||||
|
|
@ -87,7 +95,7 @@ export fn z_file_from_url(
|
||||||
|
|
||||||
export fn z_file_path(handle: ?*c.uhdk_file) c.uhdk_bytes {
|
export fn z_file_path(handle: ?*c.uhdk_file) c.uhdk_bytes {
|
||||||
const object = runtime.fromObjectHandle(handle);
|
const object = runtime.fromObjectHandle(handle);
|
||||||
return .{ .ptr = object.payload.file.path.ptr, .len = object.payload.file.path.len };
|
return .{ .ptr = object.payload.file.native_path.ptr, .len = object.payload.file.native_path.len };
|
||||||
}
|
}
|
||||||
|
|
||||||
export fn z_menu_items(handle: ?*c.uhdk_menu, len: [*c]u64) [*c]const c.uhdk_menu_item {
|
export fn z_menu_items(handle: ?*c.uhdk_menu, len: [*c]u64) [*c]const c.uhdk_menu_item {
|
||||||
|
|
@ -10,7 +10,7 @@ comptime {
|
||||||
checkExports(@import("api/files.zig"));
|
checkExports(@import("api/files.zig"));
|
||||||
checkExports(@import("api/menus.zig"));
|
checkExports(@import("api/menus.zig"));
|
||||||
checkExports(@import("api/desktop.zig"));
|
checkExports(@import("api/desktop.zig"));
|
||||||
_ = @import("macos/callbacks.zig");
|
_ = @import("callbacks.zig");
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
|
|
||||||
|
|
@ -294,6 +294,7 @@ pub fn applicationMain(application: *Application) void {
|
||||||
application.worker_id = std.Thread.getCurrentId();
|
application.worker_id = std.Thread.getCurrentId();
|
||||||
application.unlock();
|
application.unlock();
|
||||||
application.entry.?(toAppHandle(application), application.user);
|
application.entry.?(toAppHandle(application), application.user);
|
||||||
|
if (@import("builtin").os.tag == .windows) _ = c.z_native_gl(null, 4, null);
|
||||||
application.lock();
|
application.lock();
|
||||||
application.stopping = true;
|
application.stopping = true;
|
||||||
application.worker_done = true;
|
application.worker_done = true;
|
||||||
|
|
@ -364,7 +365,11 @@ pub fn applicationError(err: anyerror) abi.Status {
|
||||||
pub fn destroyObject(object: *Resource) void {
|
pub fn destroyObject(object: *Resource) void {
|
||||||
if (!object.alive) return;
|
if (!object.alive) return;
|
||||||
std.debug.assert(checkThread(object.app) == abi.OK);
|
std.debug.assert(checkThread(object.app) == abi.OK);
|
||||||
if (object.payload == .gl) std.debug.assert(!object.payload.gl.bracket);
|
if (object.payload == .gl) {
|
||||||
|
std.debug.assert(!object.payload.gl.bracket);
|
||||||
|
if (@import("builtin").os.tag == .windows and object.native != null)
|
||||||
|
_ = c.z_native_gl(object.native, 8, null);
|
||||||
|
}
|
||||||
if (object.payload == .window) if (object.payload.window.context) |ctx| {
|
if (object.payload == .window) if (object.payload.window.context) |ctx| {
|
||||||
destroyObject(ctx);
|
destroyObject(ctx);
|
||||||
object.payload.window.context = null;
|
object.payload.window.context = null;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue