error.go (6582B)
1 package glfw 2 3 //#define GLFW_INCLUDE_NONE 4 //#include "glfw/include/GLFW/glfw3.h" 5 //void glfwSetErrorCallbackCB(); 6 import "C" 7 8 import ( 9 "fmt" 10 "log" 11 ) 12 13 // ErrorCode corresponds to an error code. 14 type ErrorCode int 15 16 // Error codes that are translated to panics and the programmer should not 17 // expect to handle. 18 const ( 19 notInitialized ErrorCode = C.GLFW_NOT_INITIALIZED // GLFW has not been initialized. 20 noCurrentContext ErrorCode = C.GLFW_NO_CURRENT_CONTEXT // No context is current. 21 invalidEnum ErrorCode = C.GLFW_INVALID_ENUM // One of the enum parameters for the function was given an invalid enum. 22 invalidValue ErrorCode = C.GLFW_INVALID_VALUE // One of the parameters for the function was given an invalid value. 23 outOfMemory ErrorCode = C.GLFW_OUT_OF_MEMORY // A memory allocation failed. 24 platformError ErrorCode = C.GLFW_PLATFORM_ERROR // A platform-specific error occurred that does not match any of the more specific categories. 25 ) 26 27 const ( 28 // APIUnavailable is the error code used when GLFW could not find support 29 // for the requested client API on the system. 30 // 31 // The installed graphics driver does not support the requested client API, 32 // or does not support it via the chosen context creation backend. Below 33 // are a few examples. 34 // 35 // Some pre-installed Windows graphics drivers do not support OpenGL. AMD 36 // only supports OpenGL ES via EGL, while Nvidia and Intel only supports it 37 // via a WGL or GLX extension. OS X does not provide OpenGL ES at all. The 38 // Mesa EGL, OpenGL and OpenGL ES libraries do not interface with the 39 // Nvidia binary driver. 40 APIUnavailable ErrorCode = C.GLFW_API_UNAVAILABLE 41 42 // VersionUnavailable is the error code used when the requested OpenGL or 43 // OpenGL ES (including any requested profile or context option) is not 44 // available on this machine. 45 // 46 // The machine does not support your requirements. If your application is 47 // sufficiently flexible, downgrade your requirements and try again. 48 // Otherwise, inform the user that their machine does not match your 49 // requirements. 50 // 51 // Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 52 // 5.0 comes out before the 4.x series gets that far, also fail with this 53 // error and not GLFW_INVALID_VALUE, because GLFW cannot know what future 54 // versions will exist. 55 VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE 56 57 // FormatUnavailable is the error code used for both window creation and 58 // clipboard querying format errors. 59 // 60 // If emitted during window creation, the requested pixel format is not 61 // supported. This means one or more hard constraints did not match any of 62 // the available pixel formats. If your application is sufficiently 63 // flexible, downgrade your requirements and try again. Otherwise, inform 64 // the user that their machine does not match your requirements. 65 // 66 // If emitted when querying the clipboard, the contents of the clipboard 67 // could not be converted to the requested format. You should ignore the 68 // error or report it to the user, as appropriate. 69 FormatUnavailable ErrorCode = C.GLFW_FORMAT_UNAVAILABLE 70 ) 71 72 func (e ErrorCode) String() string { 73 switch e { 74 case notInitialized: 75 return "NotInitialized" 76 case noCurrentContext: 77 return "NoCurrentContext" 78 case invalidEnum: 79 return "InvalidEnum" 80 case invalidValue: 81 return "InvalidValue" 82 case outOfMemory: 83 return "OutOfMemory" 84 case platformError: 85 return "PlatformError" 86 case APIUnavailable: 87 return "APIUnavailable" 88 case VersionUnavailable: 89 return "VersionUnavailable" 90 case FormatUnavailable: 91 return "FormatUnavailable" 92 default: 93 return fmt.Sprintf("ErrorCode(%d)", e) 94 } 95 } 96 97 // Error holds error code and description. 98 type Error struct { 99 Code ErrorCode 100 Desc string 101 } 102 103 // Error prints the error code and description in a readable format. 104 func (e *Error) Error() string { 105 return fmt.Sprintf("%s: %s", e.Code.String(), e.Desc) 106 } 107 108 // Note: There are many cryptic caveats to proper error handling here. 109 // See: https://github.com/go-gl/glfw3/pull/86 110 111 // Holds the value of the last error. 112 var lastError = make(chan *Error, 1) 113 114 //export goErrorCB 115 func goErrorCB(code C.int, desc *C.char) { 116 flushErrors() 117 err := &Error{ErrorCode(code), C.GoString(desc)} 118 select { 119 case lastError <- err: 120 default: 121 fmt.Println("GLFW: An uncaught error has occurred:", err) 122 fmt.Println("GLFW: Please report this bug in the Go package immediately.") 123 } 124 } 125 126 // Set the glfw callback internally 127 func init() { 128 C.glfwSetErrorCallbackCB() 129 } 130 131 // flushErrors is called by Terminate before it actually calls C.glfwTerminate, 132 // this ensures that any uncaught errors buffered in lastError are printed 133 // before the program exits. 134 func flushErrors() { 135 err := fetchError() 136 if err != nil { 137 fmt.Println("GLFW: An uncaught error has occurred:", err) 138 fmt.Println("GLFW: Please report this bug in the Go package immediately.") 139 } 140 } 141 142 // acceptError fetches the next error from the error channel, it accepts only 143 // errors with one of the given error codes. If any other error is encountered, 144 // a panic will occur. 145 // 146 // Platform errors are always printed, for information why please see: 147 // 148 // https://github.com/go-gl/glfw/issues/127 149 // 150 func acceptError(codes ...ErrorCode) error { 151 // Grab the next error, if there is one. 152 err := fetchError() 153 if err == nil { 154 return nil 155 } 156 157 // Only if the error has the specific error code accepted by the caller, do 158 // we return the error. 159 for _, code := range codes { 160 if err.Code == code { 161 return err 162 } 163 } 164 165 // The error isn't accepted by the caller. If the error code is not a code 166 // defined in the GLFW C documentation as a programmer error, then the 167 // caller should have accepted it. This is effectively a bug in this 168 // package. 169 switch err.Code { 170 case platformError: 171 log.Println(err) 172 return nil 173 case notInitialized, noCurrentContext, invalidEnum, invalidValue, outOfMemory: 174 panic(err) 175 default: 176 fmt.Println("GLFW: An invalid error was not accepted by the caller:", err) 177 fmt.Println("GLFW: Please report this bug in the Go package immediately.") 178 panic(err) 179 } 180 } 181 182 // panicError is a helper used by functions which expect no errors (except 183 // programmer errors) to occur. It will panic if it finds any such error. 184 func panicError() { 185 err := acceptError() 186 if err != nil { 187 panic(err) 188 } 189 } 190 191 // fetchError fetches the next error from the error channel, it does not block 192 // and returns nil if there is no error present. 193 func fetchError() *Error { 194 select { 195 case err := <-lastError: 196 return err 197 default: 198 return nil 199 } 200 }