error.go 6.4 KB

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