diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..1c9e43f16 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/mach"] + path = vendor/mach + url = https://github.com/hexops/mach.git diff --git a/build.zig b/build.zig index 3c2057289..35544d4ac 100644 --- a/build.zig +++ b/build.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const glfw = @import("vendor/mach/glfw/build.zig"); const Builder = std.build.Builder; const LibExeObjStep = std.build.LibExeObjStep; @@ -10,10 +11,8 @@ pub fn build(b: *std.build.Builder) void { exe.setTarget(target); exe.setBuildMode(mode); exe.install(); - exe.linkLibC(); - exe.linkSystemLibrary("glfw3"); - // exe.linkSystemLibrary("X11"); - // exe.linkSystemLibrary("xcb"); + exe.addPackagePath("glfw", "vendor/mach/glfw/src/main.zig"); + glfw.link(b, exe, .{}); const run_cmd = exe.run(); run_cmd.step.dependOn(b.getInstallStep()); diff --git a/nix/devshell.nix b/nix/devshell.nix index 78d429dd6..6a52ed515 100644 --- a/nix/devshell.nix +++ b/nix/devshell.nix @@ -5,9 +5,8 @@ , scdoc , zig -, glfw +, libGL , libX11 -, vulkan-headers }: mkShell rec { name = "ghostty"; @@ -20,8 +19,8 @@ buildInputs = [ ] ++ lib.optionals stdenv.isLinux [ - glfw libX11 - vulkan-headers ]; + + LD_LIBRARY_PATH="${libGL}/lib"; } diff --git a/src/glfw/c.zig b/src/glfw/c.zig deleted file mode 100644 index 6a6b352ab..000000000 --- a/src/glfw/c.zig +++ /dev/null @@ -1,4 +0,0 @@ -pub usingnamespace @cImport({ - @cDefine("GLFW_INCLUDE_VULKAN", "1"); - @cInclude("GLFW/glfw3.h"); -}); diff --git a/src/glfw/errors.zig b/src/glfw/errors.zig deleted file mode 100644 index d9d4103e0..000000000 --- a/src/glfw/errors.zig +++ /dev/null @@ -1,124 +0,0 @@ -const c = @import("c.zig"); - -/// Errors that GLFW can produce. -pub const Error = error{ - /// GLFW has not been initialized. - /// - /// This occurs if a GLFW function was called that must not be called unless the library is - /// initialized. - NotInitialized, - - /// No context is current for this thread. - /// - /// This occurs if a GLFW function was called that needs and operates on the current OpenGL or - /// OpenGL ES context but no context is current on the calling thread. One such function is - /// glfw.SwapInterval. - NoCurrentContext, - - /// One of the arguments to the function was an invalid enum value. - /// - /// One of the arguments to the function was an invalid enum value, for example requesting - /// glfw.red_bits with glfw.getWindowAttrib. - InvalidEnum, - - /// One of the arguments to the function was an invalid value. - /// - /// One of the arguments to the function was an invalid value, for example requesting a - /// non-existent OpenGL or OpenGL ES version like 2.7. - /// - /// Requesting a valid but unavailable OpenGL or OpenGL ES version will instead result in a - /// glfw.Error.VersionUnavailable error. - InvalidValue, - - /// A memory allocation failed. - OutOfMemory, - - /// GLFW could not find support for the requested API on the system. - /// - /// The installed graphics driver does not support the requested API, or does not support it - /// via the chosen context creation backend. Below are a few examples. - /// - /// Some pre-installed Windows graphics drivers do not support OpenGL. AMD only supports - /// OpenGL ES via EGL, while Nvidia and Intel only support it via a WGL or GLX extension. macOS - /// does not provide OpenGL ES at all. The Mesa EGL, OpenGL and OpenGL ES libraries do not - /// interface with the Nvidia binary driver. Older graphics drivers do not support Vulkan. - APIUnavailable, - - /// The requested OpenGL or OpenGL ES version (including any requested context or framebuffer - /// hints) is not available on this machine. - /// - /// The machine does not support your requirements. If your application is sufficiently - /// flexible, downgrade your requirements and try again. Otherwise, inform the user that their - /// machine does not match your requirements. - /// - /// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 comes out - /// before the 4.x series gets that far, also fail with this error and not glfw.Error.InvalidValue, - /// because GLFW cannot know what future versions will exist. - VersionUnavailable, - - /// A platform-specific error occurred that does not match any of the more specific categories. - /// - /// A bug or configuration error in GLFW, the underlying operating system or its drivers, or a - /// lack of required resources. Report the issue to our [issue tracker](https://github.com/glfw/glfw/issues). - PlatformError, - - /// The requested format is not supported or available. - /// - /// If emitted during window creation, the requested pixel format is not supported. - /// - /// If emitted when querying the clipboard, the contents of the clipboard could not be - /// converted to the requested format. - /// - /// If emitted during window creation, one or more hard constraints did not match any of the - /// available pixel formats. If your application is sufficiently flexible, downgrade your - /// requirements and try again. Otherwise, inform the user that their machine does not match - /// your requirements. - /// - /// If emitted when querying the clipboard, ignore the error or report it to the user, as - /// appropriate. - FormatUnavailable, - - /// The specified window does not have an OpenGL or OpenGL ES context. - /// - /// A window that does not have an OpenGL or OpenGL ES context was passed to a function that - /// requires it to have one. - NoWindowContext, -}; - -fn convertError(e: c_int) Error!void { - return switch (e) { - c.GLFW_NO_ERROR => {}, - c.GLFW_NOT_INITIALIZED => Error.NotInitialized, - c.GLFW_NO_CURRENT_CONTEXT => Error.NoCurrentContext, - c.GLFW_INVALID_ENUM => Error.InvalidEnum, - c.GLFW_INVALID_VALUE => Error.InvalidValue, - c.GLFW_OUT_OF_MEMORY => Error.OutOfMemory, - c.GLFW_API_UNAVAILABLE => Error.APIUnavailable, - c.GLFW_VERSION_UNAVAILABLE => Error.VersionUnavailable, - c.GLFW_PLATFORM_ERROR => Error.PlatformError, - c.GLFW_FORMAT_UNAVAILABLE => Error.FormatUnavailable, - c.GLFW_NO_WINDOW_CONTEXT => Error.NoWindowContext, - else => unreachable, - }; -} - -/// Returns and clears the last error for the calling thread. -/// -/// This function returns and clears the error code of the last error that occurred on the calling -/// thread, and optionally a UTF-8 encoded human-readable description of it. If no error has -/// occurred since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is -/// set to `NULL`. -/// -/// * @param[in] description Where to store the error description pointer, or `NULL`. -/// @return The last error code for the calling thread, or @ref GLFW_NO_ERROR (zero). -/// -/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it -/// yourself. It is guaranteed to be valid only until the next error occurs or the library is -/// terminated. -/// -/// @remark This function may be called before @ref glfwInit. -/// -/// @thread_safety This function may be called from any thread. -pub inline fn getError() Error!void { - return convertError(c.glfwGetError(null)); -} diff --git a/src/glfw/glfw.zig b/src/glfw/glfw.zig deleted file mode 100644 index baea33ebe..000000000 --- a/src/glfw/glfw.zig +++ /dev/null @@ -1,2 +0,0 @@ -pub const c = @import("c.zig"); -pub const errors = @import("errors.zig"); diff --git a/src/main.zig b/src/main.zig index fd8a78948..49d028618 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,20 +1,16 @@ const std = @import("std"); -const glfw = @import("glfw/glfw.zig"); +const glfw = @import("glfw"); pub fn main() !void { - // Iniialize GLFW - if (glfw.c.glfwInit() != glfw.c.GLFW_TRUE) return glfw.errors.getError(); - defer glfw.c.glfwTerminate(); + try glfw.init(.{}); + defer glfw.terminate(); - // Create our initial window - const window = glfw.c.glfwCreateWindow(640, 480, "My Title", null, null) orelse - return glfw.errors.getError(); - defer glfw.c.glfwDestroyWindow(window); + // Create our window + const window = try glfw.Window.create(640, 480, "Hello, mach-glfw!", null, null, .{}); + defer window.destroy(); - // Setup OpenGL - glfw.c.glfwMakeContextCurrent(window); - - while (glfw.c.glfwWindowShouldClose(window) == glfw.c.GLFW_FALSE) { - glfw.c.glfwWaitEvents(); + // Wait for the user to close the window. + while (!window.shouldClose()) { + try glfw.pollEvents(); } } diff --git a/vendor/mach b/vendor/mach new file mode 160000 index 000000000..d26c76b07 --- /dev/null +++ b/vendor/mach @@ -0,0 +1 @@ +Subproject commit d26c76b074c243365de086ed56448455b7988b69