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:
- 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.
- 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)`
@ -103,7 +102,7 @@ Now in your code you may import and use GLFW:
const glfw = @import("glfw");
/// 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 });
}
@ -131,19 +130,10 @@ pub fn main() !void {
## 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.
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:
- `Window.setIcon`
@ -152,6 +142,37 @@ Here is a rough list of functionality Wayland does not support:
- `Monitor.setGamma`
- `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 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 c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Image = @import("Image.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.
/// @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.
///
/// @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.
///
/// 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.
///
/// 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
/// 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.
///
@ -183,7 +181,7 @@ test "create" {
const allocator = testing.allocator;
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -199,7 +197,7 @@ test "create" {
test "createStandard" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);

View file

@ -7,8 +7,6 @@ const std = @import("std");
const c = @import("c.zig").c;
const Window = @import("Window.zig");
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Action = @import("action.zig").Action;
const GamepadAxis = @import("gamepad_axis.zig").GamepadAxis;
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.
///
/// 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.
///
@ -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.
///
/// 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.
///
/// @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.
///
/// 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.
///
/// @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.
///
/// 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.
///
/// @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
/// 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.
///
/// @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.
///
/// 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.
///
/// @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.
///
/// Possible errors include glfw.Error.InvalidValue.
/// Possible errors include glfw.ErrorCode.InvalidValue.
/// Returns a boolean indicating success.
///
/// @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.
///
/// Possible errors include glfw.Error.InvalidEnum.
/// Possible errors include glfw.ErrorCode.InvalidEnum.
/// Additionally returns false in the event of an error.
///
/// @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
/// 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.
///
/// @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
/// gamepad mapping.
///
/// Possible errors include glfw.Error.InvalidEnum.
/// Possible errors include glfw.ErrorCode.InvalidEnum.
/// Returns null in the event of an error.
///
/// @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" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -478,7 +476,7 @@ test "present" {
test "getAxes" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -491,7 +489,7 @@ test "getAxes" {
test "getButtons" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -504,7 +502,7 @@ test "getButtons" {
test "getHats" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -524,7 +522,7 @@ test "getHats" {
test "getName" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -537,7 +535,7 @@ test "getName" {
test "getGUID" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -550,7 +548,7 @@ test "getGUID" {
test "setUserPointer_syntax" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -566,7 +564,7 @@ test "setUserPointer_syntax" {
test "getUserPointer_syntax" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -582,7 +580,7 @@ test "getUserPointer_syntax" {
test "setCallback" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -604,7 +602,7 @@ test "updateGamepadMappings_syntax" {
test "isGamepad" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -617,7 +615,7 @@ test "isGamepad" {
test "getGamepadName" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -630,7 +628,7 @@ test "getGamepadName" {
test "getGamepadState" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);

View file

@ -5,8 +5,6 @@ const mem = std.mem;
const testing = std.testing;
const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const GammaRamp = @import("GammaRamp.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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
///
/// @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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// A zero value is returned in the event of an error.
///
/// @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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// A zero value is returned in the event of an error.
///
/// @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
/// by refresh rate.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error.
///
/// 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
/// iconified.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// Additionally returns null in the event of an error.
///
/// @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.
///
/// 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
/// and emits glfw.Error.PlatformError.
/// and emits glfw.ErrorCode.PlatformError.
///
/// @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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// Additionally returns null in the event of an error.
///
/// 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
///
/// 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.
///
/// 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
/// monitor. On win32, the gamma ramp size must be 256.
///
/// 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.
///
@ -402,7 +400,7 @@ pub inline fn setCallback(comptime callback: ?fn (monitor: Monitor, event: Event
test "getAll" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -416,7 +414,7 @@ test "getAll" {
test "getPrimary" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -428,7 +426,7 @@ test "getPrimary" {
test "getPos" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -443,7 +441,7 @@ test "getPos" {
test "getWorkarea" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -458,7 +456,7 @@ test "getWorkarea" {
test "getPhysicalSize" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -473,7 +471,7 @@ test "getPhysicalSize" {
test "getContentScale" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -488,7 +486,7 @@ test "getContentScale" {
test "getName" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -503,7 +501,7 @@ test "getName" {
test "userPointer" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -523,7 +521,7 @@ test "userPointer" {
test "setCallback" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -540,7 +538,7 @@ test "setCallback" {
test "getVideoModes" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -559,7 +557,7 @@ test "getVideoModes" {
test "getVideoMode" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -575,7 +573,7 @@ test "getVideoMode" {
test "set_getGammaRamp" {
const allocator = testing.allocator;
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
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 c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
///
/// @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
/// 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.
///
/// 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.
///
/// @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" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -62,7 +60,7 @@ test "setClipboardString" {
test "getClipboardString" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);

View file

@ -5,7 +5,7 @@ const mem = @import("std").mem;
const c = @import("c.zig").c;
/// Errors that GLFW can produce.
pub const Error = error{
pub const ErrorCode = error{
/// GLFW has not been initialized.
///
/// 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.
///
/// Requesting a valid but unavailable OpenGL or OpenGL ES version will instead result in a
/// glfw.Error.VersionUnavailable error.
/// glfw.ErrorCode.VersionUnavailable error.
InvalidValue,
/// A memory allocation failed.
@ -56,7 +56,7 @@ pub const Error = error{
/// machine does not match your requirements.
///
/// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 comes out
/// before the 4.x series gets that far, also fail with this error and not glfw.Error.InvalidValue,
/// 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.
VersionUnavailable,
@ -148,36 +148,49 @@ pub const Error = error{
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) {
c.GLFW_NO_ERROR => {},
c.GLFW_NOT_INITIALIZED => Error.NotInitialized,
c.GLFW_NO_CURRENT_CONTEXT => Error.NoCurrentContext,
c.GLFW_INVALID_ENUM => Error.InvalidEnum,
c.GLFW_INVALID_VALUE => Error.InvalidValue,
c.GLFW_OUT_OF_MEMORY => Error.OutOfMemory,
c.GLFW_API_UNAVAILABLE => Error.APIUnavailable,
c.GLFW_VERSION_UNAVAILABLE => Error.VersionUnavailable,
c.GLFW_PLATFORM_ERROR => Error.PlatformError,
c.GLFW_FORMAT_UNAVAILABLE => Error.FormatUnavailable,
c.GLFW_NO_WINDOW_CONTEXT => Error.NoWindowContext,
c.GLFW_CURSOR_UNAVAILABLE => Error.CursorUnavailable,
c.GLFW_FEATURE_UNAVAILABLE => Error.FeatureUnavailable,
c.GLFW_FEATURE_UNIMPLEMENTED => Error.FeatureUnimplemented,
c.GLFW_PLATFORM_UNAVAILABLE => Error.PlatformUnavailable,
c.GLFW_NOT_INITIALIZED => ErrorCode.NotInitialized,
c.GLFW_NO_CURRENT_CONTEXT => ErrorCode.NoCurrentContext,
c.GLFW_INVALID_ENUM => ErrorCode.InvalidEnum,
c.GLFW_INVALID_VALUE => ErrorCode.InvalidValue,
c.GLFW_OUT_OF_MEMORY => ErrorCode.OutOfMemory,
c.GLFW_API_UNAVAILABLE => ErrorCode.APIUnavailable,
c.GLFW_VERSION_UNAVAILABLE => ErrorCode.VersionUnavailable,
c.GLFW_PLATFORM_ERROR => ErrorCode.PlatformError,
c.GLFW_FORMAT_UNAVAILABLE => ErrorCode.FormatUnavailable,
c.GLFW_NO_WINDOW_CONTEXT => ErrorCode.NoWindowContext,
c.GLFW_CURSOR_UNAVAILABLE => ErrorCode.CursorUnavailable,
c.GLFW_FEATURE_UNAVAILABLE => ErrorCode.FeatureUnavailable,
c.GLFW_FEATURE_UNIMPLEMENTED => ErrorCode.FeatureUnimplemented,
c.GLFW_PLATFORM_UNAVAILABLE => ErrorCode.PlatformUnavailable,
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.
///
/// This function returns and clears the error code of the last error that occurred on the calling
/// thread, and optionally a UTF-8 encoded human-readable description of it. If no error has
/// occurred since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is
/// set to `NULL`.
///
/// * @param[in] description Where to store the error description pointer, or `NULL`.
/// @return The last error code for the calling thread, or @ref GLFW_NO_ERROR (zero).
/// thread, along with a UTF-8 encoded human-readable description of it. If no error has occurred
/// since the last call, it returns GLFW_NO_ERROR (zero) and the description pointer is set to
/// `NULL`.
///
/// @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
@ -186,15 +199,42 @@ fn convertError(e: c_int) Error!void {
/// @remark This function may be called before @ref glfwInit.
///
/// @thread_safety This function may be called from any thread.
pub inline fn getError() Error!void {
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));
}
/// Returns and clears the last error for the calling thread. If no error is present, this function
/// panics.
pub inline fn mustGetError() Error {
try getError();
@panic("glfw: mustGetError called but no error is present");
/// Returns and clears the last error code for the calling thread. If no error is present, this
/// function panics.
pub inline fn mustGetErrorCode() ErrorCode {
try getErrorCode();
@panic("glfw: mustGetErrorCode called but no error is present");
}
/// 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.
///
/// @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;
const error_code = c.glfwGetError(&desc);
convertError(error_code) catch {
if (error_code != c.GLFW_NO_ERROR) {
return mem.sliceTo(desc, 0);
};
}
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.
///
/// 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.
///
/// @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| {
const CWrapper = struct {
pub fn errorCallbackWrapper(err_int: c_int, c_description: [*c]const u8) callconv(.C) void {
if (convertError(err_int)) |_| {
// This means the error was `GLFW_NO_ERROR`
return;
} else |err| {
user_callback(err, mem.sliceTo(c_description, 0));
}
convertError(err_int) catch |error_code| {
user_callback(error_code, mem.sliceTo(c_description, 0));
};
}
};
@ -269,9 +314,9 @@ pub fn setErrorCallback(comptime callback: ?fn (error_code: Error, description:
_ = c.glfwSetErrorCallback(null);
}
test "errorCallback" {
test "set error callback" {
const TestStruct = struct {
pub fn callback(_: Error, _: [:0]const u8) void {}
pub fn callback(_: ErrorCode, _: [:0]const u8) void {}
};
setErrorCallback(TestStruct.callback);
}
@ -279,3 +324,15 @@ test "errorCallback" {
test "error string" {
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 cc = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
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.
/// @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.
///
/// 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).
/// @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.
///
/// @thread_safety This function may be called from any thread.
@ -245,7 +243,7 @@ pub const Key = enum(c_int) {
test "getName" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -257,7 +255,7 @@ test "getName" {
test "getScancode" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);

View file

@ -4,18 +4,20 @@ const testing = std.testing;
const c = @import("c.zig").c;
const key = @import("key.zig");
const errors = @import("errors.zig");
/// Possible value for various window hints, etc.
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 mustGetError = errors.mustGetError;
pub const getErrorCode = errors.getErrorCode;
pub const mustGetErrorCode = errors.mustGetErrorCode;
pub const getErrorString = errors.getErrorString;
pub const mustGetErrorString = errors.mustGetErrorString;
pub const setErrorCallback = errors.setErrorCallback;
pub const clearError = errors.clearError;
pub const ErrorCode = errors.ErrorCode;
pub const Error = errors.Error;
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
/// 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.
///
/// @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.
///
/// 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
/// this function is called.
@ -263,7 +265,7 @@ pub const PlatformType = enum(c_int) {
/// @param hint: The init hint to set.
/// @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.
///
@ -346,7 +348,7 @@ pub fn platformSupported(platform: PlatformType) bool {
///
/// 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.
///
@ -381,7 +383,7 @@ pub inline fn pollEvents() void {
///
/// 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.
///
@ -420,7 +422,7 @@ pub inline fn waitEvents() void {
///
/// @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.
///
@ -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
/// 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.
///
@ -454,8 +456,8 @@ pub inline fn postEmptyEvent() void {
///
/// 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
/// attempt to enable raw motion on a system that does not support it, glfw.Error.PlatformError will
/// be emitted.
/// attempt to enable raw motion on a system that does not support it, glfw.ErrorCode.PlatformError
/// will be emitted.
///
/// 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
@ -473,7 +475,7 @@ pub inline fn rawMouseMotionSupported() bool {
}
pub fn basicTest() !void {
defer getError() catch {}; // clear any error we generate
defer clearError(); // clear any error we generate
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);
@ -481,8 +483,8 @@ pub fn basicTest() !void {
defer terminate();
const window = Window.create(640, 480, "GLFW example", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{getErrorString()});
std.process.exit(0); // note: we don't exit(1) here because our CI can't open windows
std.log.warn("failed to create window: {?s}", .{getErrorString()});
return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
};
defer window.destroy();
@ -511,7 +513,7 @@ test "pollEvents" {
}
test "pollEvents" {
defer getError() catch {}; // clear any error we generate
defer clearError(); // clear any error we generate
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);
@ -522,7 +524,7 @@ test "pollEvents" {
}
test "waitEventsTimeout" {
defer getError() catch {}; // clear any error we generate
defer clearError(); // clear any error we generate
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);
@ -533,7 +535,7 @@ test "waitEventsTimeout" {
}
test "postEmptyEvent_and_waitEvents" {
defer getError() catch {}; // clear any error we generate
defer clearError(); // clear any error we generate
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);
@ -545,7 +547,7 @@ test "postEmptyEvent_and_waitEvents" {
}
test "rawMouseMotionSupported" {
defer getError() catch {}; // clear any error we generate
defer clearError(); // clear any error we generate
if (!init(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{getErrorString()});
std.process.exit(1);

View file

@ -3,8 +3,6 @@ const std = @import("std");
const Window = @import("Window.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");
@ -114,7 +112,7 @@ pub fn Native(comptime options: BackendOptions) type {
/// ```
/// 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.
///
/// 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.
///
/// 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.
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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
///
/// 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.
///
/// Possible errors include glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.PlatformError.
/// Returns null in the event of an error.
///
/// 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.
///
/// Possible errors include glfw.Error.NoWindowContext.
/// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error.
///
/// 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.
///
/// Possible errors include glfw.Error.NoWindowContext.
/// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error.
///
/// 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.
///
/// Possible errors include glfw.Error.NoWindowContext.
/// Possible errors include glfw.ErrorCode.NoWindowContext.
/// Returns null in the event of an error.
///
/// 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.
///
/// 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.
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.
///
/// 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.
///
/// 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.
///
/// 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.
///
/// 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.
///
/// 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.
pub fn getOSMesaContext(window: Window) ?*anyopaque {

View file

@ -2,8 +2,6 @@ const std = @import("std");
const c = @import("c.zig").c;
const Window = @import("Window.zig");
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
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.
///
/// 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
/// 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.
///
@ -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.
///
/// 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
/// 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
/// 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
/// 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.
///
/// 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
/// 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.
/// @return `true` if the extension is available, or `false` otherwise.
///
/// Possible errors include glfw.Error.NoCurrentContext, glfw.Error.InvalidValue
/// and glfw.Error.PlatformError.
/// Possible errors include glfw.ErrorCode.NoCurrentContext, glfw.ErrorCode.InvalidValue
/// and glfw.ErrorCode.PlatformError.
///
/// @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.
///
/// 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,
/// `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
/// 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
/// occur this function will panic. You should ensure a valid OpenGL context exists and the
/// glfw.ErrorCode.NotInitialized, glfw.ErrorCode.NoCurrentContext, or glfw.ErrorCode.PlatformError
/// would occur this function will panic. You should ensure a valid OpenGL context exists and the
/// GLFW is initialized before calling this function.
///
/// 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" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -179,8 +177,8 @@ test "makeContextCurrent" {
defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
};
defer window.destroy();
@ -189,7 +187,7 @@ test "makeContextCurrent" {
test "getCurrentContext" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -202,7 +200,7 @@ test "getCurrentContext" {
test "swapInterval" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -210,8 +208,8 @@ test "swapInterval" {
defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
};
defer window.destroy();
@ -221,7 +219,7 @@ test "swapInterval" {
test "getProcAddress" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -229,8 +227,8 @@ test "getProcAddress" {
defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
};
defer window.destroy();
@ -240,7 +238,7 @@ test "getProcAddress" {
test "extensionSupported" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -248,8 +246,8 @@ test "extensionSupported" {
defer glfw.terminate();
const window = Window.create(640, 480, "Hello, Zig!", null, null, .{}) orelse {
std.log.err("failed to create window: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
std.log.warn("failed to create window: {?s}", .{glfw.getErrorString()});
return error.SkipZigTest; // note: we don't exit(1) here because our CI can't open windows
};
defer window.destroy();

View file

@ -1,8 +1,6 @@
const std = @import("std");
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");
@ -46,7 +44,7 @@ pub inline fn getTime() f64 {
///
/// @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
/// 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" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -120,7 +118,7 @@ test "getTime" {
test "setTime" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -132,7 +130,7 @@ test "setTime" {
test "getTimerValue" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -144,7 +142,7 @@ test "getTimerValue" {
test "getTimerFrequency" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);

View file

@ -1,8 +1,6 @@
const std = @import("std");
const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
const getError = @import("errors.zig").getError;
const Window = @import("Window.zig");
const internal_debug = @import("internal_debug.zig");
@ -64,13 +62,13 @@ pub inline fn vulkanSupported() bool {
/// directly to the `VkInstanceCreateInfo` struct.
///
/// 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
/// minimally available.
/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
/// least minimally available.
///
/// 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.
///
/// Possible errors include glfw.Error.APIUnavailable.
/// Possible errors include glfw.ErrorCode.APIUnavailable.
/// Returns null in the event of an error.
///
/// 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`
///
/// 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
/// minimally available.
/// glfw.ErrorCode.APIUnavailable error. Call glfw.vulkanSupported to check whether Vulkan is at
/// least minimally available.
///
/// This function is equivalent to calling `vkGetInstanceProcAddr` with a platform-specific query
/// 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
/// 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.
///
/// @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
/// 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.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.
/// @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.
///
/// 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.
///
/// 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.
///
/// 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`
/// 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.
///
/// 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`.
///
/// 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
/// 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.
///
/// 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" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -259,7 +257,7 @@ test "vulkanSupported" {
test "getRequiredInstanceExtensions" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);
@ -271,7 +269,7 @@ test "getRequiredInstanceExtensions" {
test "getInstanceProcAddress" {
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(.{})) {
std.log.err("failed to initialize GLFW: {?s}", .{glfw.getErrorString()});
std.process.exit(1);