internal/cglfw: fix errors to be close to internal/glfw

Updates #2703
This commit is contained in:
Hajime Hoshi 2023-10-07 22:48:41 +09:00
parent 6dc375f7a6
commit ad0b61c022
3 changed files with 37 additions and 86 deletions

View File

@ -17,6 +17,7 @@ package cglfw
import "C" import "C"
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
) )
@ -24,107 +25,55 @@ import (
// ErrorCode corresponds to an error code. // ErrorCode corresponds to an error code.
type ErrorCode int type ErrorCode int
// Error codes that are translated to panics and the programmer should not
// expect to handle.
const ( const (
notInitialized ErrorCode = C.GLFW_NOT_INITIALIZED // GLFW has not been initialized. NotInitialized = ErrorCode(0x00010001)
noCurrentContext ErrorCode = C.GLFW_NO_CURRENT_CONTEXT // No context is current. NoCurrentContext = ErrorCode(0x00010002)
invalidEnum ErrorCode = C.GLFW_INVALID_ENUM // One of the enum parameters for the function was given an invalid enum. InvalidEnum = ErrorCode(0x00010003)
invalidValue ErrorCode = C.GLFW_INVALID_VALUE // One of the parameters for the function was given an invalid value. InvalidValue = ErrorCode(0x00010004)
outOfMemory ErrorCode = C.GLFW_OUT_OF_MEMORY // A memory allocation failed. OutOfMemory = ErrorCode(0x00010005)
platformError ErrorCode = C.GLFW_PLATFORM_ERROR // A platform-specific error occurred that does not match any of the more specific categories. APIUnavailable = ErrorCode(0x00010006)
VersionUnavailable = ErrorCode(0x00010007)
PlatformError = ErrorCode(0x00010008)
FormatUnavailable = ErrorCode(0x00010009)
NoWindowContext = ErrorCode(0x0001000A)
) )
const ( func (e ErrorCode) Error() string {
// APIUnavailable is the error code used when GLFW could not find support
// for the requested client API on the system.
//
// The installed graphics driver does not support the requested client API,
// or does not support it via the chosen context creation backend. Below
// are a few examples.
//
// Some pre-installed Windows graphics drivers do not support OpenGL. AMD
// only supports OpenGL ES via EGL, while Nvidia and Intel only supports it
// via a WGL or GLX extension. OS X does not provide OpenGL ES at all. The
// Mesa EGL, OpenGL and OpenGL ES libraries do not interface with the
// Nvidia binary driver.
APIUnavailable ErrorCode = C.GLFW_API_UNAVAILABLE
// VersionUnavailable is the error code used when the requested OpenGL or
// OpenGL ES (including any requested profile or context option) is not
// available on this machine.
//
// The machine does not support your requirements. If your application is
// sufficiently flexible, downgrade your requirements and try again.
// Otherwise, inform the user that their machine does not match your
// requirements.
//
// Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if
// 5.0 comes out before the 4.x series gets that far, also fail with this
// error and not GLFW_INVALID_VALUE, because GLFW cannot know what future
// versions will exist.
VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE
// FormatUnavailable is the error code used for both window creation and
// clipboard querying format errors.
//
// If emitted during window creation, the requested pixel format is not
// supported. This means one or more hard constraints did not match any of
// the available pixel formats. If your application is sufficiently
// flexible, downgrade your requirements and try again. Otherwise, inform
// the user that their machine does not match your requirements.
//
// If emitted when querying the clipboard, the contents of the clipboard
// could not be converted to the requested format. You should ignore the
// error or report it to the user, as appropriate.
FormatUnavailable ErrorCode = C.GLFW_FORMAT_UNAVAILABLE
)
func (e ErrorCode) String() string {
switch e { switch e {
case notInitialized: case NotInitialized:
return "NotInitialized" return "the GLFW library is not initialized"
case noCurrentContext: case NoCurrentContext:
return "NoCurrentContext" return "there is no current context"
case invalidEnum: case InvalidEnum:
return "InvalidEnum" return "invalid argument for enum parameter"
case invalidValue: case InvalidValue:
return "InvalidValue" return "invalid value for parameter"
case outOfMemory: case OutOfMemory:
return "OutOfMemory" return "out of memory"
case platformError:
return "PlatformError"
case APIUnavailable: case APIUnavailable:
return "APIUnavailable" return "the requested API is unavailable"
case VersionUnavailable: case VersionUnavailable:
return "VersionUnavailable" return "the requested API version is unavailable"
case PlatformError:
return "a platform-specific error occurred"
case FormatUnavailable: case FormatUnavailable:
return "FormatUnavailable" return "the requested format is unavailable"
case NoWindowContext:
return "the specified window has no context"
default: default:
return fmt.Sprintf("ErrorCode(%d)", e) return fmt.Sprintf("GLFW error (%d)", e)
} }
} }
// Error holds error code and description.
type Error struct {
Code ErrorCode
Desc string
}
// Error prints the error code and description in a readable format.
func (e *Error) Error() string {
return fmt.Sprintf("%s: %s", e.Code.String(), e.Desc)
}
// Note: There are many cryptic caveats to proper error handling here. // Note: There are many cryptic caveats to proper error handling here.
// See: https://github.com/go-gl/glfw3/pull/86 // See: https://github.com/go-gl/glfw3/pull/86
// lastError holds the value of the last error. // lastError holds the value of the last error.
var lastError = make(chan *Error, 1) var lastError = make(chan error, 1)
//export goErrorCB //export goErrorCB
func goErrorCB(code C.int, desc *C.char) { func goErrorCB(code C.int, desc *C.char) {
err := &Error{ErrorCode(code), C.GoString(desc)} err := fmt.Errorf("glfw: %s: %w", C.GoString(desc), ErrorCode(code))
select { select {
case lastError <- err: case lastError <- err:
default: default:
@ -142,7 +91,7 @@ func init() {
func fetchErrorIgnoringPlatformError() error { func fetchErrorIgnoringPlatformError() error {
select { select {
case err := <-lastError: case err := <-lastError:
if err.Code == platformError { if errors.Is(err, PlatformError) {
fmt.Fprintln(os.Stderr, err) fmt.Fprintln(os.Stderr, err)
return nil return nil
} }

View File

@ -12,6 +12,7 @@ package cglfw
import "C" import "C"
import ( import (
"errors"
"unsafe" "unsafe"
) )
@ -116,7 +117,7 @@ func GetClipboardString() (string, error) {
cs := C.glfwGetClipboardString(nil) cs := C.glfwGetClipboardString(nil)
if cs == nil { if cs == nil {
if err := fetchErrorIgnoringPlatformError(); err != nil { if err := fetchErrorIgnoringPlatformError(); err != nil {
if cerr, ok := err.(*Error); ok && cerr.Code == FormatUnavailable { if errors.Is(err, FormatUnavailable) {
return "", nil return "", nil
} }
return "", err return "", err

View File

@ -58,6 +58,7 @@ package cglfw
import "C" import "C"
import ( import (
"errors"
"image" "image"
"image/draw" "image/draw"
"sync" "sync"
@ -1054,7 +1055,7 @@ func (w *Window) GetClipboardString() (string, error) {
cs := C.glfwGetClipboardString(w.data) cs := C.glfwGetClipboardString(w.data)
if cs == nil { if cs == nil {
if err := fetchErrorIgnoringPlatformError(); err != nil { if err := fetchErrorIgnoringPlatformError(); err != nil {
if cerr, ok := err.(*Error); ok && cerr.Code == FormatUnavailable { if errors.Is(err, FormatUnavailable) {
return "", nil return "", nil
} }
return "", err return "", err