glfw: refactor getError and related functions

`getError()` now returns a struct `Error` containing `error_code` and
`description`. Rationale: retrieving the error code with the previous
implementation of `getError()` caused `getErrorString()` to return
null (the reverse is also true). The new implementation allows both
values to be retrieved at once.

The previous `getError()` function has been renamed to
`getErrorCode()` to reflect the fact that it returns a simple Zig
error rather than the `Error` struct. The error set returned by
`getErrorCode()` is now named `ErrorCode` rather than `Error`.

The behavior of the `getError()` family of functions clearing the
stored error is unchanged. However, since all code that used
`defer glfw.getError() catch {}` to explicitly clear errors had to be
refactored, a new `glfw.clearError()` function that returns void is
now available to make this operation more explicit.

Additionally, `mustGetError()` is now `mustGetErrorCode()`, and new
functions `mustGetError()` and `mustGetErrorString()` have been added
which wrap `getError()` and `getErrorString()` but panic if no error
is actually available.

Tests and API documentation had to be refactored across all of
`mach/glfw`. This commit also takes the opportunity to skip tests
involving window creation on CI so that other tests may still execute
normally.
This commit is contained in:
Lue 2023-01-10 23:25:00 +00:00 committed by Stephen Gutekanst
parent 20fc0272f0
commit 097bea84ab
13 changed files with 505 additions and 443 deletions

View file

@ -20,7 +20,6 @@ There are 130+ tests, and CI tests on all major platforms as well as cross-compi
Why create a ziggified GLFW wrapper, instead of just using `@cImport` and interfacing with GLFW directly? You get: Why create a ziggified GLFW wrapper, instead of just using `@cImport` and interfacing with GLFW directly? You get:
- Errors as [zig errors](https://ziglang.org/documentation/master/#Errors) instead of via a callback function.
- `true` and `false` instead of `c.GLFW_TRUE` and `c.GLFW_FALSE` constants. - `true` and `false` instead of `c.GLFW_TRUE` and `c.GLFW_FALSE` constants.
- Generics, so you can just use `window.hint` instead of `glfwWindowHint`, `glfwWindowHintString`, etc. - Generics, so you can just use `window.hint` instead of `glfwWindowHint`, `glfwWindowHintString`, etc.
- **Enums**, always know what value a GLFW function can accept as everything is strictly typed. And use the nice Zig syntax to access enums, like `window.getKey(.escape)` instead of `c.glfwGetKey(window, c.GLFW_KEY_ESCAPE)` - **Enums**, always know what value a GLFW function can accept as everything is strictly typed. And use the nice Zig syntax to access enums, like `window.getKey(.escape)` instead of `c.glfwGetKey(window, c.GLFW_KEY_ESCAPE)`
@ -103,7 +102,7 @@ Now in your code you may import and use GLFW:
const glfw = @import("glfw"); const glfw = @import("glfw");
/// Default GLFW error handling callback /// Default GLFW error handling callback
fn errorCallback(error_code: glfw.Error, description: [:0]const u8) void { fn errorCallback(error_code: glfw.ErrorCode, description: [:0]const u8) void {
std.log.err("glfw: {}: {s}\n", .{ error_code, description }); std.log.err("glfw: {}: {s}\n", .{ error_code, description });
} }
@ -131,19 +130,10 @@ pub fn main() !void {
## A warning about error handling ## A warning about error handling
Unless the action you're performing is truly critical to your application continuing further, you should avoid using `try`. Unless the action you're performing is truly critical to your application continuing further, you should avoid terminating on error.
This is because GLFW unfortunately must return errors for _a large portion_ of its functionality on some platforms, but especially for Wayland - so ideally your application is resiliant to such errors and merely e.g. logs failures that are not critical. This is because GLFW unfortunately must return errors for _a large portion_ of its functionality on some platforms, but especially for Wayland - so ideally your application is resiliant to such errors and merely e.g. logs failures that are not critical.
Instead of `try window.getPos()` for example, you may use:
```zig
const pos = window.getPos() catch |err| {
std.log.err("failed to get window position: error={}\n", .{err});
return;
};
```
Here is a rough list of functionality Wayland does not support: Here is a rough list of functionality Wayland does not support:
- `Window.setIcon` - `Window.setIcon`
@ -152,6 +142,37 @@ Here is a rough list of functionality Wayland does not support:
- `Monitor.setGamma` - `Monitor.setGamma`
- `Monitor.getGammaRamp`, `Monitor.setGammaRamp` - `Monitor.getGammaRamp`, `Monitor.setGammaRamp`
For example, `window.getPos()` will always return x=0, y=0 on Wayland due to lack of platform support.
Ignoring this error is a reasonable choice for most applications.
However, errors like this can still be caught and handled:
```zig
const pos = window.getPos();
// Option 1: convert a GLFW error into a Zig error.
glfw.getErrorCode() catch |err| {
std.log.err("failed to get window position: error={}", .{err});
return err; // Or fall back to an alternative implementation.
};
// Option 2: log a human-readable description of the error.
if (glfw.getErrorString()) |description| {
std.log.err("failed to get window position: {s}", .{description});
// ...
}
// Option 3: use a combination of the above approaches.
if (glfw.getError()) |err| {
const error_code = err.error_code; // Zig error
const description = err.description; // Human-readable description
std.log.err("failed to get window position: error={}: {s}", .{error_code, description});
// ...
}
```
Note that the above example relies on GLFW's saved error being empty; otherwise, previously emitted errors may be mistaken for an error caused by `window.getPos()`.
If your application frequently ignores errors, it may be necessary to call `glfw.clearError()` or `defer glfw.clearError()` to ensure a clean slate for future error handling.
## Join the community ## Join the community
Join the Mach engine community [on Matrix chat](https://matrix.to/#/#hexops:matrix.org) to discuss this project, ask questions, get help, etc. Join the Mach engine community [on Matrix chat](https://matrix.to/#/#hexops:matrix.org) to discuss this project, ask questions, get help, etc.

View file

@ -4,8 +4,6 @@ const std = @import("std");
const testing = std.testing; const testing = std.testing;
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Image = @import("Image.zig"); const Image = @import("Image.zig");
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -106,7 +104,7 @@ pub const Shape = enum(i32) {
/// @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. /// @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot.
/// @return The handle of the created cursor. /// @return The handle of the created cursor.
/// ///
/// Possible errors include glfw.Error.PlatformError and glfw.Error.InvalidValue /// Possible errors include glfw.ErrorCode.PlatformError and glfw.ErrorCode.InvalidValue
/// null is returned in the event of an error. /// null is returned in the event of an error.
/// ///
/// @pointer_lifetime The specified image data is copied before this function returns. /// @pointer_lifetime The specified image data is copied before this function returns.
@ -147,7 +145,7 @@ pub inline fn create(image: Image, xhot: i32, yhot: i32) ?Cursor {
/// 2. This uses a newer standard that not all cursor themes support. /// 2. This uses a newer standard that not all cursor themes support.
/// ///
/// If the requested shape is not available, this function emits a CursorUnavailable error /// If the requested shape is not available, this function emits a CursorUnavailable error
/// Possible errors include glfw.Error.PlatformError and glfw.Error.CursorUnavailable. /// Possible errors include glfw.ErrorCode.PlatformError and glfw.ErrorCode.CursorUnavailable.
/// null is returned in the event of an error. /// null is returned in the event of an error.
/// ///
/// thread_safety: This function must only be called from the main thread. /// thread_safety: This function must only be called from the main thread.
@ -167,7 +165,7 @@ pub inline fn createStandard(shape: Shape) ?Cursor {
/// If the specified cursor is current for any window, that window will be reverted to the default /// If the specified cursor is current for any window, that window will be reverted to the default
/// cursor. This does not affect the cursor mode. /// cursor. This does not affect the cursor mode.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @reentrancy This function must not be called from a callback. /// @reentrancy This function must not be called from a callback.
/// ///
@ -183,7 +181,7 @@ test "create" {
const allocator = testing.allocator; const allocator = testing.allocator;
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -199,7 +197,7 @@ test "create" {
test "createStandard" { test "createStandard" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -7,8 +7,6 @@ const std = @import("std");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Window = @import("Window.zig"); const Window = @import("Window.zig");
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Action = @import("action.zig").Action; const Action = @import("action.zig").Action;
const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis; const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
const GamepadButton = @import("gamepad_button.zig").GamepadButton; const GamepadButton = @import("gamepad_button.zig").GamepadButton;
@ -80,7 +78,7 @@ const GamepadState = extern struct {
/// ///
/// @return `true` if the joystick is present, or `false` otherwise. /// @return `true` if the joystick is present, or `false` otherwise.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
/// ///
@ -101,7 +99,7 @@ pub inline fn present(self: Joystick) bool {
/// ///
/// @return An array of axis values, or null if the joystick is not present. /// @return An array of axis values, or null if the joystick is not present.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// null is additionally returned in the event of an error. /// null is additionally returned in the event of an error.
/// ///
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
@ -136,7 +134,7 @@ pub inline fn getAxes(self: Joystick) ?[]const f32 {
/// ///
/// @return An array of button states, or null if the joystick is not present. /// @return An array of button states, or null if the joystick is not present.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// null is additionally returned in the event of an error. /// null is additionally returned in the event of an error.
/// ///
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
@ -184,7 +182,7 @@ pub inline fn getButtons(self: Joystick) ?[]const u8 {
/// ///
/// @return An array of hat states, or null if the joystick is not present. /// @return An array of hat states, or null if the joystick is not present.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// null is additionally returned in the event of an error. /// null is additionally returned in the event of an error.
/// ///
/// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned array is allocated and freed by GLFW. You should not free it
@ -214,7 +212,7 @@ pub inline fn getHats(self: Joystick) ?[]const Hat {
/// @return The UTF-8 encoded name of the joystick, or null if the joystick is not present or an /// @return The UTF-8 encoded name of the joystick, or null if the joystick is not present or an
/// error occurred. /// error occurred.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// null is additionally returned in the event of an error. /// null is additionally returned in the event of an error.
/// ///
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
@ -251,7 +249,7 @@ pub inline fn getName(self: Joystick) ?[:0]const u8 {
/// ///
/// @return The UTF-8 encoded GUID of the joystick, or null if the joystick is not present. /// @return The UTF-8 encoded GUID of the joystick, or null if the joystick is not present.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// null is additionally returned in the event of an error. /// null is additionally returned in the event of an error.
/// ///
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
@ -364,7 +362,7 @@ pub inline fn setCallback(comptime callback: ?fn (joystick: Joystick, event: Eve
/// ///
/// @param[in] string The string containing the gamepad mappings. /// @param[in] string The string containing the gamepad mappings.
/// ///
/// Possible errors include glfw.Error.InvalidValue. /// Possible errors include glfw.ErrorCode.InvalidValue.
/// Returns a boolean indicating success. /// Returns a boolean indicating success.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -388,7 +386,7 @@ pub inline fn updateGamepadMappings(gamepad_mappings: [*:0]const u8) bool {
/// ///
/// @return `true` if a joystick is both present and has a gamepad mapping, or `false` otherwise. /// @return `true` if a joystick is both present and has a gamepad mapping, or `false` otherwise.
/// ///
/// Possible errors include glfw.Error.InvalidEnum. /// Possible errors include glfw.ErrorCode.InvalidEnum.
/// Additionally returns false in the event of an error. /// Additionally returns false in the event of an error.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -412,7 +410,7 @@ pub inline fn isGamepad(self: Joystick) bool {
/// @return The UTF-8 encoded name of the gamepad, or null if the joystick is not present or does /// @return The UTF-8 encoded name of the gamepad, or null if the joystick is not present or does
/// not have a mapping. /// not have a mapping.
/// ///
/// Possible errors include glfw.Error.InvalidEnum. /// Possible errors include glfw.ErrorCode.InvalidEnum.
/// Additionally returns null in the event of an error. /// Additionally returns null in the event of an error.
/// ///
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
@ -450,7 +448,7 @@ pub inline fn getGamepadName(self: Joystick) ?[:0]const u8 {
/// @return the gamepad input state if successful, or null if no joystick is connected or it has no /// @return the gamepad input state if successful, or null if no joystick is connected or it has no
/// gamepad mapping. /// gamepad mapping.
/// ///
/// Possible errors include glfw.Error.InvalidEnum. /// Possible errors include glfw.ErrorCode.InvalidEnum.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -465,7 +463,7 @@ pub inline fn getGamepadState(self: Joystick) ?GamepadState {
test "present" { test "present" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -478,7 +476,7 @@ test "present" {
test "getAxes" { test "getAxes" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -491,7 +489,7 @@ test "getAxes" {
test "getButtons" { test "getButtons" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -504,7 +502,7 @@ test "getButtons" {
test "getHats" { test "getHats" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -524,7 +522,7 @@ test "getHats" {
test "getName" { test "getName" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -537,7 +535,7 @@ test "getName" {
test "getGUID" { test "getGUID" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -550,7 +548,7 @@ test "getGUID" {
test "setUserPointer_syntax" { test "setUserPointer_syntax" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -566,7 +564,7 @@ test "setUserPointer_syntax" {
test "getUserPointer_syntax" { test "getUserPointer_syntax" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -582,7 +580,7 @@ test "getUserPointer_syntax" {
test "setCallback" { test "setCallback" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -604,7 +602,7 @@ test "updateGamepadMappings_syntax" {
test "isGamepad" { test "isGamepad" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -617,7 +615,7 @@ test "isGamepad" {
test "getGamepadName" { test "getGamepadName" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -630,7 +628,7 @@ test "getGamepadName" {
test "getGamepadState" { test "getGamepadState" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -5,8 +5,6 @@ const mem = std.mem;
const testing = std.testing; const testing = std.testing;
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const GammaRamp = @import("GammaRamp.zig"); const GammaRamp = @import("GammaRamp.zig");
const VideoMode = @import("VideoMode.zig"); const VideoMode = @import("VideoMode.zig");
@ -27,7 +25,7 @@ const Pos = struct {
/// Returns the position of the monitor's viewport on the virtual screen. /// Returns the position of the monitor's viewport on the virtual screen.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
/// ///
@ -55,7 +53,7 @@ const Workarea = struct {
/// Retrieves the work area of the monitor. /// Retrieves the work area of the monitor.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// A zero value is returned in the event of an error. /// A zero value is returned in the event of an error.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -114,7 +112,7 @@ const ContentScale = struct {
/// Returns the content scale for the monitor. /// Returns the content scale for the monitor.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// A zero value is returned in the event of an error. /// A zero value is returned in the event of an error.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -188,7 +186,7 @@ pub inline fn getUserPointer(self: Monitor, comptime T: type) ?*T {
/// then by resolution area (the product of width and height), then resolution width and finally /// then by resolution area (the product of width and height), then resolution width and finally
/// by refresh rate. /// by refresh rate.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// The returned slice memory is owned by the caller. /// The returned slice memory is owned by the caller.
@ -218,7 +216,7 @@ pub inline fn getVideoModes(self: Monitor, allocator: mem.Allocator) mem.Allocat
/// full screen window for that monitor, the return value will depend on whether that window is /// full screen window for that monitor, the return value will depend on whether that window is
/// iconified. /// iconified.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// Additionally returns null in the event of an error. /// Additionally returns null in the event of an error.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -241,10 +239,10 @@ pub inline fn getVideoMode(self: Monitor) ?VideoMode {
/// ///
/// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint. /// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint.
/// ///
/// Possible errors include glfw.Error.InvalidValue and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidValue and glfw.ErrorCode.PlatformError.
/// ///
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented /// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
/// and emits glfw.Error.PlatformError. /// and emits glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
/// ///
@ -263,11 +261,11 @@ pub inline fn setGamma(self: Monitor, gamma: f32) void {
/// ///
/// This function returns the current gamma ramp of the specified monitor. /// This function returns the current gamma ramp of the specified monitor.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// Additionally returns null in the event of an error. /// Additionally returns null in the event of an error.
/// ///
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented /// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
/// and returns glfw.Error.PlatformError. /// and returns glfw.ErrorCode.PlatformError.
/// TODO: Is the documentation obsolete? On wayland the error returned is FeatureUnavailable /// TODO: Is the documentation obsolete? On wayland the error returned is FeatureUnavailable
/// ///
/// The returned gamma ramp is `.owned = true` by GLFW, and is valid until the monitor is /// The returned gamma ramp is `.owned = true` by GLFW, and is valid until the monitor is
@ -294,13 +292,13 @@ pub inline fn getGammaRamp(self: Monitor) ?GammaRamp {
/// ///
/// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint. /// For gamma correct rendering with OpenGL or OpenGL ES, see the glfw.srgb_capable hint.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// The size of the specified gamma ramp should match the size of the current ramp for that /// The size of the specified gamma ramp should match the size of the current ramp for that
/// monitor. On win32, the gamma ramp size must be 256. /// monitor. On win32, the gamma ramp size must be 256.
/// ///
/// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented /// wayland: Gamma handling is a privileged protocol, this function will thus never be implemented
/// and emits glfw.Error.PlatformError. /// and emits glfw.ErrorCode.PlatformError.
/// ///
/// @pointer_lifetime The specified gamma ramp is copied before this function returns. /// @pointer_lifetime The specified gamma ramp is copied before this function returns.
/// ///
@ -402,7 +400,7 @@ pub inline fn setCallback(comptime callback: ?fn (monitor: Monitor, event: Event
test "getAll" { test "getAll" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -416,7 +414,7 @@ test "getAll" {
test "getPrimary" { test "getPrimary" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -428,7 +426,7 @@ test "getPrimary" {
test "getPos" { test "getPos" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -443,7 +441,7 @@ test "getPos" {
test "getWorkarea" { test "getWorkarea" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -458,7 +456,7 @@ test "getWorkarea" {
test "getPhysicalSize" { test "getPhysicalSize" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -473,7 +471,7 @@ test "getPhysicalSize" {
test "getContentScale" { test "getContentScale" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -488,7 +486,7 @@ test "getContentScale" {
test "getName" { test "getName" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -503,7 +501,7 @@ test "getName" {
test "userPointer" { test "userPointer" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -523,7 +521,7 @@ test "userPointer" {
test "setCallback" { test "setCallback" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -540,7 +538,7 @@ test "setCallback" {
test "getVideoModes" { test "getVideoModes" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -559,7 +557,7 @@ test "getVideoModes" {
test "getVideoMode" { test "getVideoMode" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -575,7 +573,7 @@ test "getVideoMode" {
test "set_getGammaRamp" { test "set_getGammaRamp" {
const allocator = testing.allocator; const allocator = testing.allocator;
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -12,7 +10,7 @@ const internal_debug = @import("internal_debug.zig");
/// ///
/// @param[in] string A UTF-8 encoded string. /// @param[in] string A UTF-8 encoded string.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @pointer_lifetime The specified string is copied before this function returns. /// @pointer_lifetime The specified string is copied before this function returns.
/// ///
@ -28,11 +26,11 @@ pub inline fn setClipboardString(value: [*:0]const u8) void {
/// ///
/// This function returns the contents of the system clipboard, if it contains or is convertible to /// This function returns the contents of the system clipboard, if it contains or is convertible to
/// a UTF-8 encoded string. If the clipboard is empty or if its contents cannot be converted, /// a UTF-8 encoded string. If the clipboard is empty or if its contents cannot be converted,
/// glfw.Error.FormatUnavailable is returned. /// glfw.ErrorCode.FormatUnavailable is returned.
/// ///
/// @return The contents of the clipboard as a UTF-8 encoded string. /// @return The contents of the clipboard as a UTF-8 encoded string.
/// ///
/// Possible errors include glfw.Error.FormatUnavailable and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.FormatUnavailable and glfw.ErrorCode.PlatformError.
/// null is returned in the event of an error. /// null is returned in the event of an error.
/// ///
/// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it /// @pointer_lifetime The returned string is allocated and freed by GLFW. You should not free it
@ -50,7 +48,7 @@ pub inline fn getClipboardString() ?[:0]const u8 {
test "setClipboardString" { test "setClipboardString" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -62,7 +60,7 @@ test "setClipboardString" {
test "getClipboardString" { test "getClipboardString" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -5,7 +5,7 @@ const mem = @import("std").mem;
const c = @import("c.zig").c; const c = @import("c.zig").c;
/// Errors that GLFW can produce. /// Errors that GLFW can produce.
pub const Error = error{ pub const ErrorCode = error{
/// GLFW has not been initialized. /// GLFW has not been initialized.
/// ///
/// This occurs if a GLFW function was called that must not be called unless the library is /// This occurs if a GLFW function was called that must not be called unless the library is
@ -31,7 +31,7 @@ pub const Error = error{
/// non-existent OpenGL or OpenGL ES version like 2.7. /// 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 /// Requesting a valid but unavailable OpenGL or OpenGL ES version will instead result in a
/// glfw.Error.VersionUnavailable error. /// glfw.ErrorCode.VersionUnavailable error.
InvalidValue, InvalidValue,
/// A memory allocation failed. /// A memory allocation failed.
@ -56,7 +56,7 @@ pub const Error = error{
/// machine does not match your requirements. /// machine does not match your requirements.
/// ///
/// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 comes out /// 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, /// before the 4.x series gets that far, also fail with this error and not glfw.ErrorCode.InvalidValue,
/// because GLFW cannot know what future versions will exist. /// because GLFW cannot know what future versions will exist.
VersionUnavailable, VersionUnavailable,
@ -148,36 +148,49 @@ pub const Error = error{
PlatformUnavailable, PlatformUnavailable,
}; };
fn convertError(e: c_int) Error!void { /// An error produced by GLFW and the description associated with it.
pub const Error = struct {
error_code: ErrorCode,
description: [:0]const u8,
};
fn convertError(e: c_int) ErrorCode!void {
return switch (e) { return switch (e) {
c.GLFW_NO_ERROR => {}, c.GLFW_NO_ERROR => {},
c.GLFW_NOT_INITIALIZED => Error.NotInitialized, c.GLFW_NOT_INITIALIZED => ErrorCode.NotInitialized,
c.GLFW_NO_CURRENT_CONTEXT => Error.NoCurrentContext, c.GLFW_NO_CURRENT_CONTEXT => ErrorCode.NoCurrentContext,
c.GLFW_INVALID_ENUM => Error.InvalidEnum, c.GLFW_INVALID_ENUM => ErrorCode.InvalidEnum,
c.GLFW_INVALID_VALUE => Error.InvalidValue, c.GLFW_INVALID_VALUE => ErrorCode.InvalidValue,
c.GLFW_OUT_OF_MEMORY => Error.OutOfMemory, c.GLFW_OUT_OF_MEMORY => ErrorCode.OutOfMemory,
c.GLFW_API_UNAVAILABLE => Error.APIUnavailable, c.GLFW_API_UNAVAILABLE => ErrorCode.APIUnavailable,
c.GLFW_VERSION_UNAVAILABLE => Error.VersionUnavailable, c.GLFW_VERSION_UNAVAILABLE => ErrorCode.VersionUnavailable,
c.GLFW_PLATFORM_ERROR => Error.PlatformError, c.GLFW_PLATFORM_ERROR => ErrorCode.PlatformError,
c.GLFW_FORMAT_UNAVAILABLE => Error.FormatUnavailable, c.GLFW_FORMAT_UNAVAILABLE => ErrorCode.FormatUnavailable,
c.GLFW_NO_WINDOW_CONTEXT => Error.NoWindowContext, c.GLFW_NO_WINDOW_CONTEXT => ErrorCode.NoWindowContext,
c.GLFW_CURSOR_UNAVAILABLE => Error.CursorUnavailable, c.GLFW_CURSOR_UNAVAILABLE => ErrorCode.CursorUnavailable,
c.GLFW_FEATURE_UNAVAILABLE => Error.FeatureUnavailable, c.GLFW_FEATURE_UNAVAILABLE => ErrorCode.FeatureUnavailable,
c.GLFW_FEATURE_UNIMPLEMENTED => Error.FeatureUnimplemented, c.GLFW_FEATURE_UNIMPLEMENTED => ErrorCode.FeatureUnimplemented,
c.GLFW_PLATFORM_UNAVAILABLE => Error.PlatformUnavailable, c.GLFW_PLATFORM_UNAVAILABLE => ErrorCode.PlatformUnavailable,
else => unreachable, else => unreachable,
}; };
} }
/// Clears the last error and the error description pointer for the calling thread. Does nothing if
/// no error has occurred since the last call.
///
/// @remark This function may be called before @ref glfwInit.
///
/// @thread_safety This function may be called from any thread.
pub inline fn clearError() void {
_ = c.glfwGetError(null);
}
/// Returns and clears the last error for the calling thread. /// 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 /// 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 /// thread, along with a UTF-8 encoded human-readable description of it. If no error has occurred
/// occurred since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is /// since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is set to
/// set to `NULL`. /// `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 /// @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 /// yourself. It is guaranteed to be valid only until the next error occurs or the library is
@ -186,15 +199,42 @@ fn convertError(e: c_int) Error!void {
/// @remark This function may be called before @ref glfwInit. /// @remark This function may be called before @ref glfwInit.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
pub inline fn getError() Error!void { pub inline fn getError() ?Error {
var desc: [*c]const u8 = null;
convertError(c.glfwGetError(&desc)) catch |error_code| {
return .{
.error_code = error_code,
.description = mem.sliceTo(desc, 0),
};
};
return null;
}
pub inline fn mustGetError() Error {
return getError() orelse {
@panic("glfw: mustGetError called but no error is present");
};
}
/// 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. If no error has occurred since the last call, it returns GLFW_NO_ERROR (zero).
///
/// @return The last error code for the calling thread, or @ref GLFW_NO_ERROR (zero).
///
/// @remark This function may be called before @ref glfwInit.
///
/// @thread_safety This function may be called from any thread.
pub inline fn getErrorCode() ErrorCode!void {
return convertError(c.glfwGetError(null)); return convertError(c.glfwGetError(null));
} }
/// Returns and clears the last error for the calling thread. If no error is present, this function /// Returns and clears the last error code for the calling thread. If no error is present, this
/// panics. /// function panics.
pub inline fn mustGetError() Error { pub inline fn mustGetErrorCode() ErrorCode {
try getError(); try getErrorCode();
@panic("glfw: mustGetError called but no error is present"); @panic("glfw: mustGetErrorCode called but no error is present");
} }
/// Returns and clears the last error description for the calling thread. /// Returns and clears the last error description for the calling thread.
@ -209,15 +249,23 @@ pub inline fn mustGetError() Error {
/// @remark This function may be called before @ref glfwInit. /// @remark This function may be called before @ref glfwInit.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
pub inline fn getErrorString() ?[]const u8 { pub inline fn getErrorString() ?[:0]const u8 {
var desc: [*c]const u8 = null; var desc: [*c]const u8 = null;
const error_code = c.glfwGetError(&desc); const error_code = c.glfwGetError(&desc);
convertError(error_code) catch { if (error_code != c.GLFW_NO_ERROR) {
return mem.sliceTo(desc, 0); return mem.sliceTo(desc, 0);
}; }
return null; return null;
} }
/// Returns and clears the last error description for the calling thread. If no error is present,
/// this function panics.
pub inline fn mustGetErrorString() [:0]const u8 {
return getErrorString() orelse {
@panic("glfw: mustGetErrorString called but no error is present");
};
}
/// Sets the error callback. /// Sets the error callback.
/// ///
/// This function sets the error callback, which is called with an error code /// This function sets the error callback, which is called with an error code
@ -249,16 +297,13 @@ pub inline fn getErrorString() ?[]const u8 {
/// @remark This function may be called before @ref glfwInit. /// @remark This function may be called before @ref glfwInit.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description: [:0]const u8) void) void { pub fn setErrorCallback(comptime callback: ?fn (error_code: ErrorCode, description: [:0]const u8) void) void {
if (callback) |user_callback| { if (callback) |user_callback| {
const CWrapper = struct { const CWrapper = struct {
pub fn errorCallbackWrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void { pub fn errorCallbackWrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void {
if (convertError(err_int)) |_| { convertError(err_int) catch |error_code| {
// This means the error was `GLFW_NO_ERROR` user_callback(error_code, mem.sliceTo(c_description, 0));
return; };
} else |err| {
user_callback(err, mem.sliceTo(c_description, 0));
}
} }
}; };
@ -269,9 +314,9 @@ pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description:
_ = c.glfwSetErrorCallback(null); _ = c.glfwSetErrorCallback(null);
} }
test "errorCallback" { test "set error callback" {
const TestStruct = struct { const TestStruct = struct {
pub fn callback(_: Error, _: [:0]const u8) void {} pub fn callback(_: ErrorCode, _: [:0]const u8) void {}
}; };
setErrorCallback(TestStruct.callback); setErrorCallback(TestStruct.callback);
} }
@ -279,3 +324,15 @@ test "errorCallback" {
test "error string" { test "error string" {
try testing.expect(getErrorString() == null); try testing.expect(getErrorString() == null);
} }
test "error code" {
try getErrorCode();
}
test "error code and string" {
try testing.expect(getError() == null);
}
test "clear error" {
clearError();
}

View file

@ -17,8 +17,6 @@
const std = @import("std"); const std = @import("std");
const cc = @import("c.zig").c; const cc = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -204,7 +202,7 @@ pub const Key = enum(c_int) {
/// @param[in] scancode The scancode of the key to query. /// @param[in] scancode The scancode of the key to query.
/// @return The UTF-8 encoded, layout-specific name of the key, or null. /// @return The UTF-8 encoded, layout-specific name of the key, or null.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// Also returns null in the event of an error. /// Also returns null in the event of an error.
/// ///
/// The contents of the returned string may change when a keyboard layout change event is received. /// The contents of the returned string may change when a keyboard layout change event is received.
@ -233,7 +231,7 @@ pub const Key = enum(c_int) {
/// @param[in] key Any named key (see keys). /// @param[in] key Any named key (see keys).
/// @return The platform-specific scancode for the key. /// @return The platform-specific scancode for the key.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.PlatformError.
/// Additionally returns -1 in the event of an error. /// Additionally returns -1 in the event of an error.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
@ -245,7 +243,7 @@ pub const Key = enum(c_int) {
test "getName" { test "getName" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -257,7 +255,7 @@ test "getName" {
test "getScancode" { test "getScancode" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -4,18 +4,20 @@ const testing = std.testing;
const c = @import("c.zig").c; const c = @import("c.zig").c;
const key = @import("key.zig"); const key = @import("key.zig");
const errors = @import("errors.zig");
/// Possible value for various window hints, etc. /// Possible value for various window hints, etc.
pub const dont_care = c.GLFW_DONT_CARE; pub const dont_care = c.GLFW_DONT_CARE;
/// Most users should not access the error functions in this namespace, but in some rare cases they
/// may be useful.
pub const errors = @import("errors.zig");
pub const getError = errors.getError; pub const getError = errors.getError;
pub const mustGetError = errors.mustGetError; pub const mustGetError = errors.mustGetError;
pub const getErrorCode = errors.getErrorCode;
pub const mustGetErrorCode = errors.mustGetErrorCode;
pub const getErrorString = errors.getErrorString; pub const getErrorString = errors.getErrorString;
pub const mustGetErrorString = errors.mustGetErrorString;
pub const setErrorCallback = errors.setErrorCallback; pub const setErrorCallback = errors.setErrorCallback;
pub const clearError = errors.clearError;
pub const ErrorCode = errors.ErrorCode;
pub const Error = errors.Error; pub const Error = errors.Error;
pub const Action = @import("action.zig").Action; pub const Action = @import("action.zig").Action;
@ -83,7 +85,7 @@ pub fn assumeInitialized() void {
/// current environment if that category is still "C". This is because the "C" locale breaks /// current environment if that category is still "C". This is because the "C" locale breaks
/// Unicode text input. /// Unicode text input.
/// ///
/// Possible errors include glfw.Error.PlatformUnavailable, glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformUnavailable, glfw.ErrorCode.PlatformError.
/// Returns a bool indicating success. /// Returns a bool indicating success.
/// ///
/// @thread_safety This function must only be called from the main thread. /// @thread_safety This function must only be called from the main thread.
@ -149,7 +151,7 @@ pub inline fn init(hints: InitHints) bool {
/// ///
/// This function has no effect if GLFW is not initialized. /// This function has no effect if GLFW is not initialized.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// warning: The contexts of any remaining windows must not be current on any other thread when /// warning: The contexts of any remaining windows must not be current on any other thread when
/// this function is called. /// this function is called.
@ -263,7 +265,7 @@ pub const PlatformType = enum(c_int) {
/// @param hint: The init hint to set. /// @param hint: The init hint to set.
/// @param value: The new value of the init hint. /// @param value: The new value of the init hint.
/// ///
/// Possible errors include glfw.Error.InvalidEnum and glfw.Error.InvalidValue. /// Possible errors include glfw.ErrorCode.InvalidEnum and glfw.ErrorCode.InvalidValue.
/// ///
/// @remarks This function may be called before glfw.init. /// @remarks This function may be called before glfw.init.
/// ///
@ -346,7 +348,7 @@ pub fn platformSupported(platform: PlatformType) bool {
/// ///
/// Event processing is not required for joystick input to work. /// Event processing is not required for joystick input to work.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @reentrancy This function must not be called from a callback. /// @reentrancy This function must not be called from a callback.
/// ///
@ -381,7 +383,7 @@ pub inline fn pollEvents() void {
/// ///
/// Event processing is not required for joystick input to work. /// Event processing is not required for joystick input to work.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @reentrancy This function must not be called from a callback. /// @reentrancy This function must not be called from a callback.
/// ///
@ -420,7 +422,7 @@ pub inline fn waitEvents() void {
/// ///
/// @param[in] timeout The maximum amount of time, in seconds, to wait. /// @param[in] timeout The maximum amount of time, in seconds, to wait.
/// ///
/// Possible errors include glfw.Error.InvalidValue and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.InvalidValue and glfw.ErrorCode.PlatformError.
/// ///
/// @reentrancy This function must not be called from a callback. /// @reentrancy This function must not be called from a callback.
/// ///
@ -440,7 +442,7 @@ pub inline fn waitEventsTimeout(timeout: f64) void {
/// This function posts an empty event from the current thread to the event queue, causing /// This function posts an empty event from the current thread to the event queue, causing
/// glfw.waitEvents or glfw.waitEventsTimeout to return. /// glfw.waitEvents or glfw.waitEventsTimeout to return.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
/// ///
@ -454,8 +456,8 @@ pub inline fn postEmptyEvent() void {
/// ///
/// This function returns whether raw mouse motion is supported on the current system. This status /// This function returns whether raw mouse motion is supported on the current system. This status
/// does not change after GLFW has been initialized so you only need to check this once. If you /// does not change after GLFW has been initialized so you only need to check this once. If you
/// attempt to enable raw motion on a system that does not support it, glfw.Error.PlatformError will /// attempt to enable raw motion on a system that does not support it, glfw.ErrorCode.PlatformError
/// be emitted. /// will be emitted.
/// ///
/// Raw mouse motion is closer to the actual motion of the mouse across a surface. It is not /// Raw mouse motion is closer to the actual motion of the mouse across a surface. It is not
/// affected by the scaling and acceleration applied to the motion of the desktop cursor. That /// affected by the scaling and acceleration applied to the motion of the desktop cursor. That
@ -473,7 +475,7 @@ pub inline fn rawMouseMotionSupported() bool {
} }
pub fn basicTest() !void { pub fn basicTest() !void {
defer getError() catch {}; // clear any error we generate defer clearError(); // clear any error we generate
if (!init(.{})) { if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -481,8 +483,8 @@ pub fn basicTest() !void {
defer terminate(); defer terminate();
const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse { const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{getErrorString()}); std.log.warn("failed to create window: {?s}", .{getErrorString()});
std.process.exit(0); // note: we don't exit(1) here because our CI can't open windows return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
}; };
defer window.destroy(); defer window.destroy();
@ -511,7 +513,7 @@ test "pollEvents" {
} }
test "pollEvents" { test "pollEvents" {
defer getError() catch {}; // clear any error we generate defer clearError(); // clear any error we generate
if (!init(.{})) { if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -522,7 +524,7 @@ test "pollEvents" {
} }
test "waitEventsTimeout" { test "waitEventsTimeout" {
defer getError() catch {}; // clear any error we generate defer clearError(); // clear any error we generate
if (!init(.{})) { if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -533,7 +535,7 @@ test "waitEventsTimeout" {
} }
test "postEmptyEvent_and_waitEvents" { test "postEmptyEvent_and_waitEvents" {
defer getError() catch {}; // clear any error we generate defer clearError(); // clear any error we generate
if (!init(.{})) { if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -545,7 +547,7 @@ test "postEmptyEvent_and_waitEvents" {
} }
test "rawMouseMotionSupported" { test "rawMouseMotionSupported" {
defer getError() catch {}; // clear any error we generate defer clearError(); // clear any error we generate
if (!init(.{})) { if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -3,8 +3,6 @@ const std = @import("std");
const Window = @import("Window.zig"); const Window = @import("Window.zig");
const Monitor = @import("Monitor.zig"); const Monitor = @import("Monitor.zig");
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -114,7 +112,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// ``` /// ```
/// This DC is private and does not need to be released. /// This DC is private and does not need to be released.
/// ///
/// Possible errors include glfw.Error.NoWindowContext /// Possible errors include glfw.ErrorCode.NoWindowContext
/// null is returned in the event of an error. /// null is returned in the event of an error.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
@ -146,7 +144,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the `NSWindow` of the specified window. /// Returns the `NSWindow` of the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NoWindowContext.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
pub fn getNSGLContext(window: Window) u32 { pub fn getNSGLContext(window: Window) u32 {
@ -203,7 +201,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Sets the current primary selection to the specified string. /// Sets the current primary selection to the specified string.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// ///
/// The specified string is copied before this function returns. /// The specified string is copied before this function returns.
/// ///
@ -215,7 +213,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the contents of the current primary selection as a string. /// Returns the contents of the current primary selection as a string.
/// ///
/// Possible errors include glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// The returned string is allocated and freed by GLFW. You should not free it /// The returned string is allocated and freed by GLFW. You should not free it
@ -231,7 +229,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the `GLXContext` of the specified window. /// Returns the `GLXContext` of the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
@ -243,7 +241,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the `GLXWindow` of the specified window. /// Returns the `GLXWindow` of the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
@ -304,7 +302,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the `EGLContext` of the specified window. /// Returns the `EGLContext` of the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// thread_safety This function may be called from any thread. Access is not synchronized. /// thread_safety This function may be called from any thread. Access is not synchronized.
@ -317,7 +315,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the `EGLSurface` of the specified window. /// Returns the `EGLSurface` of the specified window.
/// ///
/// Possible errors include glfw.Error.NotInitalized and glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NotInitalized and glfw.ErrorCode.NoWindowContext.
/// ///
/// thread_safety This function may be called from any thread. Access is not synchronized. /// thread_safety This function may be called from any thread. Access is not synchronized.
pub fn getEGLSurface(window: Window) ?*anyopaque { pub fn getEGLSurface(window: Window) ?*anyopaque {
@ -336,7 +334,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Retrieves the color buffer associated with the specified window. /// Retrieves the color buffer associated with the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
@ -362,7 +360,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Retrieves the depth buffer associated with the specified window. /// Retrieves the depth buffer associated with the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
@ -381,7 +379,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// Returns the 'OSMesaContext' of the specified window. /// Returns the 'OSMesaContext' of the specified window.
/// ///
/// Possible errors include glfw.Error.NoWindowContext. /// Possible errors include glfw.ErrorCode.NoWindowContext.
/// ///
/// thread_safety: This function may be called from any thread. Access is not synchronized. /// thread_safety: This function may be called from any thread. Access is not synchronized.
pub fn getOSMesaContext(window: Window) ?*anyopaque { pub fn getOSMesaContext(window: Window) ?*anyopaque {

View file

@ -2,8 +2,6 @@ const std = @import("std");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Window = @import("Window.zig"); const Window = @import("Window.zig");
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -21,12 +19,12 @@ const internal_debug = @import("internal_debug.zig");
/// by setting the glfw.context_release_behavior hint. /// by setting the glfw.context_release_behavior hint.
/// ///
/// The specified window must have an OpenGL or OpenGL ES context. Specifying a window without a /// The specified window must have an OpenGL or OpenGL ES context. Specifying a window without a
/// context will generate Error.NoWindowContext. /// context will generate glfw.ErrorCode.NoWindowContext.
/// ///
/// @param[in] window The window whose context to make current, or null to /// @param[in] window The window whose context to make current, or null to
/// detach the current context. /// detach the current context.
/// ///
/// Possible errors include glfw.Error.NoWindowContext and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.NoWindowContext and glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
/// ///
@ -64,7 +62,7 @@ pub inline fn getCurrentContext() ?Window {
/// even if a frame arrives a little bit late. You can check for these extensions with glfw.extensionSupported. /// even if a frame arrives a little bit late. You can check for these extensions with glfw.extensionSupported.
/// ///
/// A context must be current on the calling thread. Calling this function without a current context /// A context must be current on the calling thread. Calling this function without a current context
/// will cause Error.NoCurrentContext. /// will cause glfw.ErrorCode.NoCurrentContext.
/// ///
/// This function does not apply to Vulkan. If you are rendering with Vulkan, see the present mode /// This function does not apply to Vulkan. If you are rendering with Vulkan, see the present mode
/// of your swapchain instead. /// of your swapchain instead.
@ -72,7 +70,7 @@ pub inline fn getCurrentContext() ?Window {
/// @param[in] interval The minimum number of screen updates to wait for until the buffers are /// @param[in] interval The minimum number of screen updates to wait for until the buffers are
/// swapped by glfw.swapBuffers. /// swapped by glfw.swapBuffers.
/// ///
/// Possible errors include glfw.Error.NoCurrentContext and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.NoCurrentContext and glfw.ErrorCode.PlatformError.
/// ///
/// This function is not called during context creation, leaving the swap interval set to whatever /// This function is not called during context creation, leaving the swap interval set to whatever
/// is the default for that API. This is done because some swap interval extensions used by /// is the default for that API. This is done because some swap interval extensions used by
@ -97,7 +95,7 @@ pub inline fn swapInterval(interval: i32) void {
/// creation API extensions. /// creation API extensions.
/// ///
/// A context must be current on the calling thread. Calling this function without a current /// A context must be current on the calling thread. Calling this function without a current
/// context will cause Error.NoCurrentContext. /// context will cause glfw.ErrorCode.NoCurrentContext.
/// ///
/// As this functions retrieves and searches one or more extension strings each call, it is /// As this functions retrieves and searches one or more extension strings each call, it is
/// recommended that you cache its results if it is going to be used frequently. The extension /// recommended that you cache its results if it is going to be used frequently. The extension
@ -109,8 +107,8 @@ pub inline fn swapInterval(interval: i32) void {
/// @param[in] extension The ASCII encoded name of the extension. /// @param[in] extension The ASCII encoded name of the extension.
/// @return `true` if the extension is available, or `false` otherwise. /// @return `true` if the extension is available, or `false` otherwise.
/// ///
/// Possible errors include glfw.Error.NoCurrentContext, glfw.Error.InvalidValue /// Possible errors include glfw.ErrorCode.NoCurrentContext, glfw.ErrorCode.InvalidValue
/// and glfw.Error.PlatformError. /// and glfw.ErrorCode.PlatformError.
/// ///
/// @thread_safety This function may be called from any thread. /// @thread_safety This function may be called from any thread.
/// ///
@ -138,7 +136,7 @@ pub const GLProc = *const fn () callconv(.C) void;
/// function (see context_glext), if it is supported by the current context. /// function (see context_glext), if it is supported by the current context.
/// ///
/// A context must be current on the calling thread. Calling this function without a current /// A context must be current on the calling thread. Calling this function without a current
/// context will cause Error.NoCurrentContext. /// context will cause glfw.ErrorCode.NoCurrentContext.
/// ///
/// This function does not apply to Vulkan. If you are rendering with Vulkan, see glfw.getInstanceProcAddress, /// This function does not apply to Vulkan. If you are rendering with Vulkan, see glfw.getInstanceProcAddress,
/// `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` instead. /// `vkGetInstanceProcAddr` and `vkGetDeviceProcAddr` instead.
@ -148,8 +146,8 @@ pub const GLProc = *const fn () callconv(.C) void;
/// ///
/// To maintain ABI compatability with the C glfwGetProcAddress, as it is commonly passed into /// To maintain ABI compatability with the C glfwGetProcAddress, as it is commonly passed into
/// libraries expecting that exact ABI, this function does not return an error. Instead, if /// libraries expecting that exact ABI, this function does not return an error. Instead, if
/// glfw.Error.NotInitialized, glfw.Error.NoCurrentContext, or glfw.Error.PlatformError would /// glfw.ErrorCode.NotInitialized, glfw.ErrorCode.NoCurrentContext, or glfw.ErrorCode.PlatformError
/// occur this function will panic. You should ensure a valid OpenGL context exists and the /// would occur this function will panic. You should ensure a valid OpenGL context exists and the
/// GLFW is initialized before calling this function. /// GLFW is initialized before calling this function.
/// ///
/// The address of a given function is not guaranteed to be the same between contexts. /// The address of a given function is not guaranteed to be the same between contexts.
@ -171,7 +169,7 @@ pub fn getProcAddress(proc_name: [*:0]const u8) callconv(.C) ?GLProc {
test "makeContextCurrent" { test "makeContextCurrent" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -179,8 +177,8 @@ test "makeContextCurrent" {
defer glfw.terminate(); defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse { const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()}); std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1); return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
}; };
defer window.destroy(); defer window.destroy();
@ -189,7 +187,7 @@ test "makeContextCurrent" {
test "getCurrentContext" { test "getCurrentContext" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -202,7 +200,7 @@ test "getCurrentContext" {
test "swapInterval" { test "swapInterval" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -210,8 +208,8 @@ test "swapInterval" {
defer glfw.terminate(); defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse { const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()}); std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1); return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
}; };
defer window.destroy(); defer window.destroy();
@ -221,7 +219,7 @@ test "swapInterval" {
test "getProcAddress" { test "getProcAddress" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -229,8 +227,8 @@ test "getProcAddress" {
defer glfw.terminate(); defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse { const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()}); std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1); return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
}; };
defer window.destroy(); defer window.destroy();
@ -240,7 +238,7 @@ test "getProcAddress" {
test "extensionSupported" { test "extensionSupported" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -248,8 +246,8 @@ test "extensionSupported" {
defer glfw.terminate(); defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse { const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()}); std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1); return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
}; };
defer window.destroy(); defer window.destroy();

View file

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -46,7 +44,7 @@ pub inline fn getTime() f64 {
/// ///
/// @param[in] time The new value, in seconds. /// @param[in] time The new value, in seconds.
/// ///
/// Possible errors include glfw.Error.InvalidValue. /// Possible errors include glfw.ErrorCode.InvalidValue.
/// ///
/// The upper limit of GLFW time is calculated as `floor((2^64 - 1) / 10^9)` and is due to /// The upper limit of GLFW time is calculated as `floor((2^64 - 1) / 10^9)` and is due to
/// implementations storing nanoseconds in 64 bits. The limit may be increased in the future. /// implementations storing nanoseconds in 64 bits. The limit may be increased in the future.
@ -108,7 +106,7 @@ pub inline fn getTimerFrequency() u64 {
test "getTime" { test "getTime" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -120,7 +118,7 @@ test "getTime" {
test "setTime" { test "setTime" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -132,7 +130,7 @@ test "setTime" {
test "getTimerValue" { test "getTimerValue" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -144,7 +142,7 @@ test "getTimerValue" {
test "getTimerFrequency" { test "getTimerFrequency" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);

View file

@ -1,8 +1,6 @@
const std = @import("std"); const std = @import("std");
const c = @import("c.zig").c; const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Window = @import("Window.zig"); const Window = @import("Window.zig");
const internal_debug = @import("internal_debug.zig"); const internal_debug = @import("internal_debug.zig");
@ -64,13 +62,13 @@ pub inline fn vulkanSupported() bool {
/// directly to the `VkInstanceCreateInfo` struct. /// directly to the `VkInstanceCreateInfo` struct.
/// ///
/// If Vulkan is not available on the machine, this function returns null and generates a /// If Vulkan is not available on the machine, this function returns null and generates a
/// glfw.Error.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at least /// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
/// minimally available. /// least minimally available.
/// ///
/// If Vulkan is available but no set of extensions allowing window surface creation was found, /// If Vulkan is available but no set of extensions allowing window surface creation was found,
/// this function returns null. You may still use Vulkan for off-screen rendering and compute work. /// this function returns null. You may still use Vulkan for off-screen rendering and compute work.
/// ///
/// Possible errors include glfw.Error.APIUnavailable. /// Possible errors include glfw.ErrorCode.APIUnavailable.
/// Returns null in the event of an error. /// Returns null in the event of an error.
/// ///
/// Additional extensions may be required by future versions of GLFW. You should check if any /// Additional extensions may be required by future versions of GLFW. You should check if any
@ -109,8 +107,8 @@ pub const VKProc = *const fn () callconv(.C) void;
/// - `vkGetInstanceProcAddr` /// - `vkGetInstanceProcAddr`
/// ///
/// If Vulkan is not available on the machine, this function returns null and generates a /// If Vulkan is not available on the machine, this function returns null and generates a
/// glfw.Error.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at least /// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
/// minimally available. /// least minimally available.
/// ///
/// This function is equivalent to calling `vkGetInstanceProcAddr` with a platform-specific query /// This function is equivalent to calling `vkGetInstanceProcAddr` with a platform-specific query
/// of the Vulkan loader as a fallback. /// of the Vulkan loader as a fallback.
@ -122,7 +120,7 @@ pub const VKProc = *const fn () callconv(.C) void;
/// ///
/// To maintain ABI compatability with the C glfwGetInstanceProcAddress, as it is commonly passed /// To maintain ABI compatability with the C glfwGetInstanceProcAddress, as it is commonly passed
/// into libraries expecting that exact ABI, this function does not return an error. Instead, if /// into libraries expecting that exact ABI, this function does not return an error. Instead, if
/// glfw.Error.NotInitialized or glfw.Error.APIUnavailable would occur this function will panic. /// glfw.ErrorCode.NotInitialized or glfw.ErrorCode.APIUnavailable would occur this function will panic.
/// You may check glfw.vulkanSupported prior to invoking this function. /// You may check glfw.vulkanSupported prior to invoking this function.
/// ///
/// @pointer_lifetime The returned function pointer is valid until the library is terminated. /// @pointer_lifetime The returned function pointer is valid until the library is terminated.
@ -141,7 +139,7 @@ pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8
/// ///
/// If Vulkan or the required window surface creation instance extensions are not available on the /// If Vulkan or the required window surface creation instance extensions are not available on the
/// machine, or if the specified instance was not created with the required extensions, this /// machine, or if the specified instance was not created with the required extensions, this
/// function returns `GLFW_FALSE` and generates a glfw.Error.APIUnavailable error. Call /// function returns `GLFW_FALSE` and generates a glfw.ErrorCode.APIUnavailable error. Call
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available and /// glfw.vulkanSupported to check whether Vulkan is at least minimally available and
/// glfw.getRequiredInstanceExtensions to check what instance extensions are required. /// glfw.getRequiredInstanceExtensions to check what instance extensions are required.
/// ///
@ -150,7 +148,7 @@ pub fn getInstanceProcAddress(vk_instance: ?*anyopaque, proc_name: [*:0]const u8
/// @param[in] queuefamily The index of the queue family to query. /// @param[in] queuefamily The index of the queue family to query.
/// @return `true` if the queue family supports presentation, or `false` otherwise. /// @return `true` if the queue family supports presentation, or `false` otherwise.
/// ///
/// Possible errors include glfw.Error.APIUnavailable and glfw.Error.PlatformError. /// Possible errors include glfw.ErrorCode.APIUnavailable and glfw.ErrorCode.PlatformError.
/// Returns false in the event of an error. /// Returns false in the event of an error.
/// ///
/// macos: This function currently always returns `true`, as the `VK_MVK_macos_surface` and /// macos: This function currently always returns `true`, as the `VK_MVK_macos_surface` and
@ -178,16 +176,16 @@ pub inline fn getPhysicalDevicePresentationSupport(
/// This function creates a Vulkan surface for the specified window. /// This function creates a Vulkan surface for the specified window.
/// ///
/// If the Vulkan loader or at least one minimally functional ICD were not found, this function /// If the Vulkan loader or at least one minimally functional ICD were not found, this function
/// returns `VK_ERROR_INITIALIZATION_FAILED` and generates a glfw.Error.APIUnavailable error. Call /// returns `VK_ERROR_INITIALIZATION_FAILED` and generates a glfw.ErrorCode.APIUnavailable error. Call
/// glfw.vulkanSupported to check whether Vulkan is at least minimally available. /// glfw.vulkanSupported to check whether Vulkan is at least minimally available.
/// ///
/// If the required window surface creation instance extensions are not available or if the /// If the required window surface creation instance extensions are not available or if the
/// specified instance was not created with these extensions enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT` /// specified instance was not created with these extensions enabled, this function returns `VK_ERROR_EXTENSION_NOT_PRESENT`
/// and generates a glfw.Error.APIUnavailable error. Call glfw.getRequiredInstanceExtensions to /// and generates a glfw.ErrorCode.APIUnavailable error. Call glfw.getRequiredInstanceExtensions to
/// check what instance extensions are required. /// check what instance extensions are required.
/// ///
/// The window surface cannot be shared with another API so the window must have been created with /// The window surface cannot be shared with another API so the window must have been created with
/// the client api hint set to `GLFW_NO_API` otherwise it generates a glfw.Error.InvalidValue error /// the client api hint set to `GLFW_NO_API` otherwise it generates a glfw.ErrorCode.InvalidValue error
/// and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`. /// and returns `VK_ERROR_NATIVE_WINDOW_IN_USE_KHR`.
/// ///
/// The window surface must be destroyed before the specified Vulkan instance. It is the /// The window surface must be destroyed before the specified Vulkan instance. It is the
@ -203,7 +201,7 @@ pub inline fn getPhysicalDevicePresentationSupport(
/// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an /// @return `VkResult` type, `VK_SUCCESS` if successful, or a Vulkan error code if an
/// error occurred. /// error occurred.
/// ///
/// Possible errors include glfw.Error.APIUnavailable, glfw.Error.PlatformError and glfw.Error.InvalidValue /// Possible errors include glfw.ErrorCode.APIUnavailable, glfw.ErrorCode.PlatformError and glfw.ErrorCode.InvalidValue
/// Returns a bool indicating success. /// Returns a bool indicating success.
/// ///
/// If an error occurs before the creation call is made, GLFW returns the Vulkan error code most /// If an error occurs before the creation call is made, GLFW returns the Vulkan error code most
@ -247,7 +245,7 @@ pub inline fn createWindowSurface(vk_instance: anytype, window: Window, vk_alloc
test "vulkanSupported" { test "vulkanSupported" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -259,7 +257,7 @@ test "vulkanSupported" {
test "getRequiredInstanceExtensions" { test "getRequiredInstanceExtensions" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);
@ -271,7 +269,7 @@ test "getRequiredInstanceExtensions" {
test "getInstanceProcAddress" { test "getInstanceProcAddress" {
const glfw = @import("main.zig"); const glfw = @import("main.zig");
defer glfw.getError() catch {}; // clear any error we generate defer glfw.clearError(); // clear any error we generate
if (!glfw.init(.{})) { if (!glfw.init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()}); std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1); std.process.exit(1);