Repository: vispy/vispy

Issue:
Replace glfw wrapper with pyglfw
At the moment, vispy has its own glfw wrapper that targets the glfw DLL, and it needs to know where you've installed GLFW.

We should probably change this to use `pip install glfw` (https://github.com/FlorianRhiem/pyGLFW)

_Originally posted by @almarklein in https://github.com/vispy/vispy/issues/2213#issuecomment-920763391_


Discussion:

Resolving patch:
diff --git a/vispy/app/backends/_glfw.py b/vispy/app/backends/_glfw.py
--- a/vispy/app/backends/_glfw.py
+++ b/vispy/app/backends/_glfw.py
@@ -13,8 +13,7 @@
 import gc
 import os
 
-from ..base import (BaseApplicationBackend, BaseCanvasBackend,
-                    BaseTimerBackend)
+from ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend
 from ...util import keys, logger
 from ...util.ptime import time
 from ... import config
@@ -24,60 +23,15 @@
 
 # -------------------------------------------------------------------- init ---
 
+glfw = None
 try:
-    from ...ext import glfw
-
-    # Map native keys to vispy keys
-    KEYMAP = {
-        glfw.GLFW_KEY_LEFT_SHIFT: keys.SHIFT,
-        glfw.GLFW_KEY_RIGHT_SHIFT: keys.SHIFT,
-        glfw.GLFW_KEY_LEFT_CONTROL: keys.CONTROL,
-        glfw.GLFW_KEY_RIGHT_CONTROL: keys.CONTROL,
-        glfw.GLFW_KEY_LEFT_ALT: keys.ALT,
-        glfw.GLFW_KEY_RIGHT_ALT: keys.ALT,
-        glfw.GLFW_KEY_LEFT_SUPER: keys.META,
-        glfw.GLFW_KEY_RIGHT_SUPER: keys.META,
-
-        glfw.GLFW_KEY_LEFT: keys.LEFT,
-        glfw.GLFW_KEY_UP: keys.UP,
-        glfw.GLFW_KEY_RIGHT: keys.RIGHT,
-        glfw.GLFW_KEY_DOWN: keys.DOWN,
-        glfw.GLFW_KEY_PAGE_UP: keys.PAGEUP,
-        glfw.GLFW_KEY_PAGE_DOWN: keys.PAGEDOWN,
-
-        glfw.GLFW_KEY_INSERT: keys.INSERT,
-        glfw.GLFW_KEY_DELETE: keys.DELETE,
-        glfw.GLFW_KEY_HOME: keys.HOME,
-        glfw.GLFW_KEY_END: keys.END,
-
-        glfw.GLFW_KEY_ESCAPE: keys.ESCAPE,
-        glfw.GLFW_KEY_BACKSPACE: keys.BACKSPACE,
-
-        glfw.GLFW_KEY_F1: keys.F1,
-        glfw.GLFW_KEY_F2: keys.F2,
-        glfw.GLFW_KEY_F3: keys.F3,
-        glfw.GLFW_KEY_F4: keys.F4,
-        glfw.GLFW_KEY_F5: keys.F5,
-        glfw.GLFW_KEY_F6: keys.F6,
-        glfw.GLFW_KEY_F7: keys.F7,
-        glfw.GLFW_KEY_F8: keys.F8,
-        glfw.GLFW_KEY_F9: keys.F9,
-        glfw.GLFW_KEY_F10: keys.F10,
-        glfw.GLFW_KEY_F11: keys.F11,
-        glfw.GLFW_KEY_F12: keys.F12,
-
-        glfw.GLFW_KEY_SPACE: keys.SPACE,
-        glfw.GLFW_KEY_ENTER: keys.ENTER,
-        '\r': keys.ENTER,
-        glfw.GLFW_KEY_TAB: keys.TAB,
-    }
-
-    BUTTONMAP = {glfw.GLFW_MOUSE_BUTTON_LEFT: 1,
-                 glfw.GLFW_MOUSE_BUTTON_RIGHT: 2,
-                 glfw.GLFW_MOUSE_BUTTON_MIDDLE: 3
-                 }
-except Exception as exp:
-    available, testable, why_not, which = False, False, str(exp), None
+    import glfw
+except ImportError:
+    why_not = "Could not import glwf, you may need to `pip install glfw` first."
+    available, testable, why_not, which = False, False, why_not, None
+except Exception as err:
+    why_not = "Error importing glfw: " + str(err)
+    available, testable, why_not, which = False, False, why_not, None
 else:
     if USE_EGL:
         available, testable, why_not = False, False, 'EGL not supported'
@@ -86,6 +40,57 @@
         available, testable, why_not = True, True, None
         which = 'glfw ' + str(glfw.__version__)
 
+if glfw:
+    # Map native keys to vispy keys
+    KEYMAP = {
+        glfw.KEY_LEFT_SHIFT: keys.SHIFT,
+        glfw.KEY_RIGHT_SHIFT: keys.SHIFT,
+        glfw.KEY_LEFT_CONTROL: keys.CONTROL,
+        glfw.KEY_RIGHT_CONTROL: keys.CONTROL,
+        glfw.KEY_LEFT_ALT: keys.ALT,
+        glfw.KEY_RIGHT_ALT: keys.ALT,
+        glfw.KEY_LEFT_SUPER: keys.META,
+        glfw.KEY_RIGHT_SUPER: keys.META,
+
+        glfw.KEY_LEFT: keys.LEFT,
+        glfw.KEY_UP: keys.UP,
+        glfw.KEY_RIGHT: keys.RIGHT,
+        glfw.KEY_DOWN: keys.DOWN,
+        glfw.KEY_PAGE_UP: keys.PAGEUP,
+        glfw.KEY_PAGE_DOWN: keys.PAGEDOWN,
+
+        glfw.KEY_INSERT: keys.INSERT,
+        glfw.KEY_DELETE: keys.DELETE,
+        glfw.KEY_HOME: keys.HOME,
+        glfw.KEY_END: keys.END,
+
+        glfw.KEY_ESCAPE: keys.ESCAPE,
+        glfw.KEY_BACKSPACE: keys.BACKSPACE,
+
+        glfw.KEY_F1: keys.F1,
+        glfw.KEY_F2: keys.F2,
+        glfw.KEY_F3: keys.F3,
+        glfw.KEY_F4: keys.F4,
+        glfw.KEY_F5: keys.F5,
+        glfw.KEY_F6: keys.F6,
+        glfw.KEY_F7: keys.F7,
+        glfw.KEY_F8: keys.F8,
+        glfw.KEY_F9: keys.F9,
+        glfw.KEY_F10: keys.F10,
+        glfw.KEY_F11: keys.F11,
+        glfw.KEY_F12: keys.F12,
+
+        glfw.KEY_SPACE: keys.SPACE,
+        glfw.KEY_ENTER: keys.ENTER,
+        '\r': keys.ENTER,
+        glfw.KEY_TAB: keys.TAB,
+    }
+
+    BUTTONMAP = {glfw.MOUSE_BUTTON_LEFT: 1,
+                 glfw.MOUSE_BUTTON_RIGHT: 2,
+                 glfw.MOUSE_BUTTON_MIDDLE: 3
+                 }
+
 MOD_KEYS = [keys.SHIFT, keys.ALT, keys.CONTROL, keys.META]
 _GLFW_INITIALIZED = False
 _VP_GLFW_ALL_WINDOWS = []
@@ -122,23 +127,23 @@ def _get_glfw_windows():
 
 def _set_config(c):
     """Set gl configuration for GLFW."""
-    glfw.glfwWindowHint(glfw.GLFW_RED_BITS, c['red_size'])
-    glfw.glfwWindowHint(glfw.GLFW_GREEN_BITS, c['green_size'])
-    glfw.glfwWindowHint(glfw.GLFW_BLUE_BITS, c['blue_size'])
-    glfw.glfwWindowHint(glfw.GLFW_ALPHA_BITS, c['alpha_size'])
-
-    glfw.glfwWindowHint(glfw.GLFW_ACCUM_RED_BITS, 0)
-    glfw.glfwWindowHint(glfw.GLFW_ACCUM_GREEN_BITS, 0)
-    glfw.glfwWindowHint(glfw.GLFW_ACCUM_BLUE_BITS, 0)
-    glfw.glfwWindowHint(glfw.GLFW_ACCUM_ALPHA_BITS, 0)
-
-    glfw.glfwWindowHint(glfw.GLFW_DEPTH_BITS, c['depth_size'])
-    glfw.glfwWindowHint(glfw.GLFW_STENCIL_BITS, c['stencil_size'])
-    # glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MAJOR, c['major_version'])
-    # glfw.glfwWindowHint(glfw.GLFW_CONTEXT_VERSION_MINOR, c['minor_version'])
-    # glfw.glfwWindowHint(glfw.GLFW_SRGB_CAPABLE, c['srgb'])
-    glfw.glfwWindowHint(glfw.GLFW_SAMPLES, c['samples'])
-    glfw.glfwWindowHint(glfw.GLFW_STEREO, c['stereo'])
+    glfw.window_hint(glfw.RED_BITS, c['red_size'])
+    glfw.window_hint(glfw.GREEN_BITS, c['green_size'])
+    glfw.window_hint(glfw.BLUE_BITS, c['blue_size'])
+    glfw.window_hint(glfw.ALPHA_BITS, c['alpha_size'])
+
+    glfw.window_hint(glfw.ACCUM_RED_BITS, 0)
+    glfw.window_hint(glfw.ACCUM_GREEN_BITS, 0)
+    glfw.window_hint(glfw.ACCUM_BLUE_BITS, 0)
+    glfw.window_hint(glfw.ACCUM_ALPHA_BITS, 0)
+
+    glfw.window_hint(glfw.DEPTH_BITS, c['depth_size'])
+    glfw.window_hint(glfw.STENCIL_BITS, c['stencil_size'])
+    # glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, c['major_version'])
+    # glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, c['minor_version'])
+    # glfw.window_hint(glfw.SRGB_CAPABLE, c['srgb'])
+    glfw.window_hint(glfw.SAMPLES, c['samples'])
+    glfw.window_hint(glfw.STEREO, c['stereo'])
     if not c['double_buffer']:
         raise RuntimeError('GLFW must double buffer, consider using a '
                            'different backend, or using double buffering')
@@ -168,7 +173,7 @@ def _vispy_get_backend_name(self):
         return 'Glfw'
 
     def _vispy_process_events(self):
-        glfw.glfwPollEvents()
+        glfw.poll_events()
         for timer in self._timers:
             timer._tick()
         wins = _get_glfw_windows()
@@ -179,7 +184,7 @@ def _vispy_process_events(self):
 
     def _vispy_run(self):
         wins = _get_glfw_windows()
-        while any(w._id is not None and not glfw.glfwWindowShouldClose(w._id)
+        while any(w._id is not None and not glfw.window_should_close(w._id)
                   for w in wins):
             self._vispy_process_events()
         self._vispy_quit()  # to clean up
@@ -199,14 +204,14 @@ def _vispy_get_native_app(self):
         global _GLFW_INITIALIZED
         if not _GLFW_INITIALIZED:
             cwd = os.getcwd()
-            glfw.glfwSetErrorCallback(_error_callback)
+            glfw.set_error_callback(_error_callback)
             try:
-                if not glfw.glfwInit():  # only ever call once
+                if not glfw.init():  # only ever call once
                     raise OSError('Could not init glfw:\n%r' % _glfw_errors)
             finally:
                 os.chdir(cwd)
-            glfw.glfwSetErrorCallback(0)
-            atexit.register(glfw.glfwTerminate)
+            glfw.set_error_callback(None)
+            atexit.register(glfw.terminate)
             _GLFW_INITIALIZED = True
         return glfw
 
@@ -230,23 +235,22 @@ def __init__(self, vispy_canvas, **kwargs):
         else:
             share = p.context.shared.ref._id
 
-        glfw.glfwWindowHint(glfw.GLFW_REFRESH_RATE, 0)  # highest possible
-        glfw.glfwSwapInterval(1 if p.vsync else 0)
-        glfw.glfwWindowHint(glfw.GLFW_RESIZABLE, int(p.resizable))
-        glfw.glfwWindowHint(glfw.GLFW_DECORATED, int(p.decorate))
-        glfw.glfwWindowHint(glfw.GLFW_VISIBLE, 0)  # start out hidden
-        glfw.glfwWindowHint(glfw.GLFW_FLOATING, int(p.always_on_top))
+        glfw.window_hint(glfw.REFRESH_RATE, 0)  # highest possible
+        glfw.window_hint(glfw.RESIZABLE, int(p.resizable))
+        glfw.window_hint(glfw.DECORATED, int(p.decorate))
+        glfw.window_hint(glfw.VISIBLE, 0)  # start out hidden
+        glfw.window_hint(glfw.FLOATING, int(p.always_on_top))
         if p.fullscreen is not False:
             self._fullscreen = True
             if p.fullscreen is True:
-                monitor = glfw.glfwGetPrimaryMonitor()
+                monitor = glfw.get_primary_monitor()
             else:
-                monitor = glfw.glfwGetMonitors()
+                monitor = glfw.get_monitors()
                 if p.fullscreen >= len(monitor):
                     raise ValueError('fullscreen must be <= %s'
                                      % len(monitor))
                 monitor = monitor[p.fullscreen]
-            use_size = glfw.glfwGetVideoMode(monitor)[:2]
+            use_size = glfw.get_video_mode(monitor)[:2]
             if use_size != tuple(p.size):
                 logger.debug('Requested size %s, will be ignored to '
                              'use fullscreen mode %s' % (p.size, use_size))
@@ -256,31 +260,34 @@ def __init__(self, vispy_canvas, **kwargs):
             monitor = None
             size = p.size
 
-        self._id = glfw.glfwCreateWindow(width=size[0], height=size[1],
-                                         title=p.title, monitor=monitor,
-                                         share=share)
+        self._id = glfw.create_window(width=size[0], height=size[1],
+                                      title=p.title, monitor=monitor,
+                                      share=share)
         if not self._id:
             raise RuntimeError('Could not create window')
 
+        glfw.make_context_current(self._id)
+        glfw.swap_interval(1 if p.vsync else 0)  # needs a valid context
+
         _VP_GLFW_ALL_WINDOWS.append(self)
         self._mod = list()
 
         # Register callbacks
-        glfw.glfwSetWindowRefreshCallback(self._id, self._on_draw)
-        glfw.glfwSetWindowSizeCallback(self._id, self._on_resize)
-        glfw.glfwSetKeyCallback(self._id, self._on_key_press)
-        glfw.glfwSetCharCallback(self._id, self._on_key_char)
-        glfw.glfwSetMouseButtonCallback(self._id, self._on_mouse_button)
-        glfw.glfwSetScrollCallback(self._id, self._on_mouse_scroll)
-        glfw.glfwSetCursorPosCallback(self._id, self._on_mouse_motion)
-        glfw.glfwSetWindowCloseCallback(self._id, self._on_close)
+        glfw.set_window_refresh_callback(self._id, self._on_draw)
+        glfw.set_window_size_callback(self._id, self._on_resize)
+        glfw.set_key_callback(self._id, self._on_key_press)
+        glfw.set_char_callback(self._id, self._on_key_char)
+        glfw.set_mouse_button_callback(self._id, self._on_mouse_button)
+        glfw.set_scroll_callback(self._id, self._on_mouse_scroll)
+        glfw.set_cursor_pos_callback(self._id, self._on_mouse_motion)
+        glfw.set_window_close_callback(self._id, self._on_close)
         self._vispy_canvas_ = None
         self._needs_draw = False
         self._vispy_canvas.set_current()
         if p.position is not None:
             self._vispy_set_position(*p.position)
         if p.show:
-            glfw.glfwShowWindow(self._id)
+            glfw.show_window(self._id)
 
         # Init
         self._initialized = True
@@ -301,42 +308,42 @@ def _vispy_set_current(self):
         if self._id is None:
             return
         # Make this the current context
-        glfw.glfwMakeContextCurrent(self._id)
+        glfw.make_context_current(self._id)
 
     def _vispy_swap_buffers(self):
         if self._id is None:
             return
         # Swap front and back buffer
-        glfw.glfwSwapBuffers(self._id)
+        glfw.swap_buffers(self._id)
 
     def _vispy_set_title(self, title):
         if self._id is None:
             return
         # Set the window title. Has no effect for widgets
-        glfw.glfwSetWindowTitle(self._id, title.encode('utf-8'))
+        glfw.set_window_title(self._id, title.encode('utf-8'))
 
     def _vispy_set_size(self, w, h):
         if self._id is None:
             return
         # Set size of the widget or window
-        glfw.glfwSetWindowSize(self._id, w, h)
+        glfw.set_window_size(self._id, w, h)
 
     def _vispy_set_position(self, x, y):
         if self._id is None:
             return
         # Set position of the widget or window. May have no effect for widgets
-        glfw.glfwSetWindowPos(self._id, x, y)
+        glfw.set_window_pos(self._id, x, y)
 
     def _vispy_set_visible(self, visible):
         # Show or hide the window or widget
         if self._id is None:
             return
         if visible:
-            glfw.glfwShowWindow(self._id)
+            glfw.show_window(self._id)
             # this ensures that the show takes effect
             self._vispy_update()
         else:
-            glfw.glfwHideWindow(self._id)
+            glfw.hide_window(self._id)
 
     def _vispy_set_fullscreen(self, fullscreen):
         logger.warn('Cannot change fullscreen mode for GLFW backend')
@@ -352,28 +359,28 @@ def _vispy_close(self):
         # Force the window or widget to shut down
         if self._id is not None:
             self._vispy_canvas = None
-            # glfw.glfwSetWindowShouldClose()  # Does not really cause a close
+            # glfw.set_window_should_close()  # Does not really cause a close
             self._vispy_set_visible(False)
             self._id, id_ = None, self._id
-            glfw.glfwDestroyWindow(id_)
+            glfw.destroy_window(id_)
             gc.collect()  # help ensure context gets destroyed
 
     def _vispy_get_size(self):
         if self._id is None:
             return
-        w, h = glfw.glfwGetWindowSize(self._id)
+        w, h = glfw.get_window_size(self._id)
         return w, h
 
     def _vispy_get_physical_size(self):
         if self._id is None:
             return
-        w, h = glfw.glfwGetFramebufferSize(self._id)
+        w, h = glfw.get_framebuffer_size(self._id)
         return w, h
 
     def _vispy_get_position(self):
         if self._id is None:
             return
-        x, y = glfw.glfwGetWindowPos(self._id)
+        x, y = glfw.get_window_pos(self._id)
         return x, y
 
     def _vispy_get_fullscreen(self):
@@ -401,13 +408,13 @@ def _on_draw(self, _id=None):
     def _on_mouse_button(self, _id, button, action, mod):
         if self._vispy_canvas is None and self._id is not None:
             return
-        pos = glfw.glfwGetCursorPos(self._id)
+        pos = glfw.get_cursor_pos(self._id)
         if button < 3:
             # Mouse click event
             button = BUTTONMAP.get(button, 0)
-            if action == glfw.GLFW_PRESS:
+            if action == glfw.PRESS:
                 fun = self._vispy_mouse_press
-            elif action == glfw.GLFW_RELEASE:
+            elif action == glfw.RELEASE:
                 fun = self._vispy_mouse_release
             else:
                 return
@@ -416,7 +423,7 @@ def _on_mouse_button(self, _id, button, action, mod):
     def _on_mouse_scroll(self, _id, x_off, y_off):
         if self._vispy_canvas is None and self._id is not None:
             return
-        pos = glfw.glfwGetCursorPos(self._id)
+        pos = glfw.get_cursor_pos(self._id)
         delta = (float(x_off), float(y_off))
         self._vispy_canvas.events.mouse_wheel(pos=pos, delta=delta,
                                               modifiers=self._mod)
@@ -430,10 +437,10 @@ def _on_key_press(self, _id, key, scancode, action, mod):
         if self._vispy_canvas is None:
             return
         key, text = self._process_key(key)
-        if action == glfw.GLFW_PRESS:
+        if action == glfw.PRESS:
             fun = self._vispy_canvas.events.key_press
             down = True
-        elif action == glfw.GLFW_RELEASE:
+        elif action == glfw.RELEASE:
             fun = self._vispy_canvas.events.key_release
             down = False
         else:
@@ -443,7 +450,7 @@ def _on_key_press(self, _id, key, scancode, action, mod):
         # NOTE: GLFW only provides localized characters via _on_key_char, so if
         # this event contains a character we store all other data and dispatch
         # it once the final unicode character is sent shortly after.
-        if text != '' and action == glfw.GLFW_PRESS:
+        if text != '' and action == glfw.PRESS:
             self._next_key_events.append((fun, key, self._mod))
         else:
             if key in self._next_key_text:
diff --git a/vispy/ext/glfw.py b/vispy/ext/glfw.py
deleted file mode 100644
--- a/vispy/ext/glfw.py
+++ /dev/null
@@ -1,649 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# -----------------------------------------------------------------------------
-#  GLFW - An OpenGL framework
-#  API version: 3.0.1
-#  WWW:         http://www.glfw.org/
-#  ----------------------------------------------------------------------------
-#  Copyright (c) 2002-2006 Marcus Geelnard
-#  Copyright (c) 2006-2010 Camilla Berglund
-#
-#  Python bindings - Copyright (c) 2013 Nicolas P. Rougier
-#
-#  This software is provided 'as-is', without any express or implied
-#  warranty. In no event will the authors be held liable for any damages
-#  arising from the use of this software.
-#
-#  Permission is granted to anyone to use this software for any purpose,
-#  including commercial applications, and to alter it and redistribute it
-#  freely, subject to the following restrictions:
-#
-#  1. The origin of this software must not be misrepresented; you must not
-#     claim that you wrote the original software. If you use this software
-#     in a product, an acknowledgment in the product documentation would
-#     be appreciated but is not required.
-#
-#  2. Altered source versions must be plainly marked as such, and must not
-#     be misrepresented as being the original software.
-#
-#  3. This notice may not be removed or altered from any source
-#     distribution.
-#
-# -----------------------------------------------------------------------------
-
-# NOTE:
-# This source has been modified from its original form by the vispy dev team
-
-import os
-import ctypes.util
-from ctypes import (Structure, POINTER, CFUNCTYPE, byref, c_char_p, c_int,
-                    c_uint, c_double, c_float, c_ushort)
-
-
-_glfw_file = None
-
-# First if there is an environment variable pointing to the library
-if 'GLFW_LIBRARY' in os.environ:
-    if os.path.exists(os.environ['GLFW_LIBRARY']):
-        _glfw_file = os.path.realpath(os.environ['GLFW_LIBRARY'])
-
-# Else, try to find it
-if _glfw_file is None:
-    order = ['glfw3', 'glfw']
-    for check in order:
-        _glfw_file = ctypes.util.find_library(check)
-        if _glfw_file is not None:
-            break
-
-# Else, we failed and exit
-if _glfw_file is None:
-    raise OSError('GLFW library not found')
-
-# Load it
-_glfw = ctypes.CDLL(_glfw_file)
-
-
-# Ensure it's new enough
-def glfwGetVersion():
-    major, minor, rev = c_int(0), c_int(0), c_int(0)
-    _glfw.glfwGetVersion(byref(major), byref(minor), byref(rev))
-    return major.value, minor.value, rev.value
-
-version = glfwGetVersion()
-
-if version[0] != 3:
-    version = '.'.join([str(v) for v in version])
-    raise OSError('Need GLFW library version 3, found version %s' % version)
-
-
-# --- Version -----------------------------------------------------------------
-GLFW_VERSION_MAJOR      = version[0]
-GLFW_VERSION_MINOR      = version[1]
-GLFW_VERSION_REVISION   = version[2]
-__version__ = GLFW_VERSION_MAJOR, GLFW_VERSION_MINOR, GLFW_VERSION_REVISION
-
-# --- Input handling definitions ----------------------------------------------
-GLFW_RELEASE            = 0
-GLFW_PRESS              = 1
-GLFW_REPEAT             = 2
-
-# --- Keys --------------------------------------------------------------------
-
-# --- The unknown key ---------------------------------------------------------
-GLFW_KEY_UNKNOWN          = -1
-
-# --- Printable keys ----------------------------------------------------------
-GLFW_KEY_SPACE            = 32
-GLFW_KEY_APOSTROPHE       = 39 # ''
-GLFW_KEY_COMMA            = 44 # ,
-GLFW_KEY_MINUS            = 45 # -
-GLFW_KEY_PERIOD           = 46 # .
-GLFW_KEY_SLASH            = 47 # /
-GLFW_KEY_0                = 48
-GLFW_KEY_1                = 49
-GLFW_KEY_2                = 50
-GLFW_KEY_3                = 51
-GLFW_KEY_4                = 52
-GLFW_KEY_5                = 53
-GLFW_KEY_6                = 54
-GLFW_KEY_7                = 55
-GLFW_KEY_8                = 56
-GLFW_KEY_9                = 57
-GLFW_KEY_SEMICOLON        = 59 # ;
-GLFW_KEY_EQUAL            = 61 # =
-GLFW_KEY_A                = 65
-GLFW_KEY_B                = 66
-GLFW_KEY_C                = 67
-GLFW_KEY_D                = 68
-GLFW_KEY_E                = 69
-GLFW_KEY_F                = 70
-GLFW_KEY_G                = 71
-GLFW_KEY_H                = 72
-GLFW_KEY_I                = 73
-GLFW_KEY_J                = 74
-GLFW_KEY_K                = 75
-GLFW_KEY_L                = 76
-GLFW_KEY_M                = 77
-GLFW_KEY_N                = 78
-GLFW_KEY_O                = 79
-GLFW_KEY_P                = 80
-GLFW_KEY_Q                = 81
-GLFW_KEY_R                = 82
-GLFW_KEY_S                = 83
-GLFW_KEY_T                = 84
-GLFW_KEY_U                = 85
-GLFW_KEY_V                = 86
-GLFW_KEY_W                = 87
-GLFW_KEY_X                = 88
-GLFW_KEY_Y                = 89
-GLFW_KEY_Z                = 90
-GLFW_KEY_LEFT_BRACKET     = 91  # [
-GLFW_KEY_BACKSLASH        = 92  # \
-GLFW_KEY_RIGHT_BRACKET    = 93  # ]
-GLFW_KEY_GRAVE_ACCENT     = 96  # `
-GLFW_KEY_WORLD_1          = 161 # non-US #1
-GLFW_KEY_WORLD_2          = 162 # non-US #2
-
-# --- Function keys -----------------------------------------------------------
-GLFW_KEY_ESCAPE           = 256
-GLFW_KEY_ENTER            = 257
-GLFW_KEY_TAB              = 258
-GLFW_KEY_BACKSPACE        = 259
-GLFW_KEY_INSERT           = 260
-GLFW_KEY_DELETE           = 261
-GLFW_KEY_RIGHT            = 262
-GLFW_KEY_LEFT             = 263
-GLFW_KEY_DOWN             = 264
-GLFW_KEY_UP               = 265
-GLFW_KEY_PAGE_UP          = 266
-GLFW_KEY_PAGE_DOWN        = 267
-GLFW_KEY_HOME             = 268
-GLFW_KEY_END              = 269
-GLFW_KEY_CAPS_LOCK        = 280
-GLFW_KEY_SCROLL_LOCK      = 281
-GLFW_KEY_NUM_LOCK         = 282
-GLFW_KEY_PRINT_SCREEN     = 283
-GLFW_KEY_PAUSE            = 284
-GLFW_KEY_F1               = 290
-GLFW_KEY_F2               = 291
-GLFW_KEY_F3               = 292
-GLFW_KEY_F4               = 293
-GLFW_KEY_F5               = 294
-GLFW_KEY_F6               = 295
-GLFW_KEY_F7               = 296
-GLFW_KEY_F8               = 297
-GLFW_KEY_F9               = 298
-GLFW_KEY_F10              = 299
-GLFW_KEY_F11              = 300
-GLFW_KEY_F12              = 301
-GLFW_KEY_F13              = 302
-GLFW_KEY_F14              = 303
-GLFW_KEY_F15              = 304
-GLFW_KEY_F16              = 305
-GLFW_KEY_F17              = 306
-GLFW_KEY_F18              = 307
-GLFW_KEY_F19              = 308
-GLFW_KEY_F20              = 309
-GLFW_KEY_F21              = 310
-GLFW_KEY_F22              = 311
-GLFW_KEY_F23              = 312
-GLFW_KEY_F24              = 313
-GLFW_KEY_F25              = 314
-GLFW_KEY_KP_0             = 320
-GLFW_KEY_KP_1             = 321
-GLFW_KEY_KP_2             = 322
-GLFW_KEY_KP_3             = 323
-GLFW_KEY_KP_4             = 324
-GLFW_KEY_KP_5             = 325
-GLFW_KEY_KP_6             = 326
-GLFW_KEY_KP_7             = 327
-GLFW_KEY_KP_8             = 328
-GLFW_KEY_KP_9             = 329
-GLFW_KEY_KP_DECIMAL       = 330
-GLFW_KEY_KP_DIVIDE        = 331
-GLFW_KEY_KP_MULTIPLY      = 332
-GLFW_KEY_KP_SUBTRACT      = 333
-GLFW_KEY_KP_ADD           = 334
-GLFW_KEY_KP_ENTER         = 335
-GLFW_KEY_KP_EQUAL         = 336
-GLFW_KEY_LEFT_SHIFT       = 340
-GLFW_KEY_LEFT_CONTROL     = 341
-GLFW_KEY_LEFT_ALT         = 342
-GLFW_KEY_LEFT_SUPER       = 343
-GLFW_KEY_RIGHT_SHIFT      = 344
-GLFW_KEY_RIGHT_CONTROL    = 345
-GLFW_KEY_RIGHT_ALT        = 346
-GLFW_KEY_RIGHT_SUPER      = 347
-GLFW_KEY_MENU             = 348
-GLFW_KEY_LAST             = GLFW_KEY_MENU
-
-
-# --- Modifiers ---------------------------------------------------------------
-GLFW_MOD_SHIFT            = 0x0001
-GLFW_MOD_CONTROL          = 0x0002
-GLFW_MOD_ALT              = 0x0004
-GLFW_MOD_SUPER            = 0x0008
-
-# --- Mouse -------------------------------------------------------------------
-GLFW_MOUSE_BUTTON_1       = 0
-GLFW_MOUSE_BUTTON_2       = 1
-GLFW_MOUSE_BUTTON_3       = 2
-GLFW_MOUSE_BUTTON_4       = 3
-GLFW_MOUSE_BUTTON_5       = 4
-GLFW_MOUSE_BUTTON_6       = 5
-GLFW_MOUSE_BUTTON_7       = 6
-GLFW_MOUSE_BUTTON_8       = 7
-GLFW_MOUSE_BUTTON_LAST    = GLFW_MOUSE_BUTTON_8
-GLFW_MOUSE_BUTTON_LEFT    = GLFW_MOUSE_BUTTON_1
-GLFW_MOUSE_BUTTON_RIGHT   = GLFW_MOUSE_BUTTON_2
-GLFW_MOUSE_BUTTON_MIDDLE  = GLFW_MOUSE_BUTTON_3
-
-
-# --- Joystick ----------------------------------------------------------------
-GLFW_JOYSTICK_1           = 0
-GLFW_JOYSTICK_2           = 1
-GLFW_JOYSTICK_3           = 2
-GLFW_JOYSTICK_4           = 3
-GLFW_JOYSTICK_5           = 4
-GLFW_JOYSTICK_6           = 5
-GLFW_JOYSTICK_7           = 6
-GLFW_JOYSTICK_8           = 7
-GLFW_JOYSTICK_9           = 8
-GLFW_JOYSTICK_10          = 9
-GLFW_JOYSTICK_11          = 10
-GLFW_JOYSTICK_12          = 11
-GLFW_JOYSTICK_13          = 12
-GLFW_JOYSTICK_14          = 13
-GLFW_JOYSTICK_15          = 14
-GLFW_JOYSTICK_16          = 15
-GLFW_JOYSTICK_LAST        = GLFW_JOYSTICK_16
-
-
-# --- Error codes -------------------------------------------------------------
-GLFW_NOT_INITIALIZED        = 0x00010001
-GLFW_NO_CURRENT_CONTEXT     = 0x00010002
-GLFW_INVALID_ENUM           = 0x00010003
-GLFW_INVALID_VALUE          = 0x00010004
-GLFW_OUT_OF_MEMORY          = 0x00010005
-GLFW_API_UNAVAILABLE        = 0x00010006
-GLFW_VERSION_UNAVAILABLE    = 0x00010007
-GLFW_PLATFORM_ERROR         = 0x00010008
-GLFW_FORMAT_UNAVAILABLE     = 0x00010009
-
-# ---
-GLFW_FOCUSED                = 0x00020001
-GLFW_ICONIFIED              = 0x00020002
-GLFW_RESIZABLE              = 0x00020003
-GLFW_VISIBLE                = 0x00020004
-GLFW_DECORATED              = 0x00020005
-GLFW_AUTO_ICONIFY           = 0x00020006
-GLFW_FLOATING               = 0x00020007
-
-# ---
-GLFW_RED_BITS               = 0x00021001
-GLFW_GREEN_BITS             = 0x00021002
-GLFW_BLUE_BITS              = 0x00021003
-GLFW_ALPHA_BITS             = 0x00021004
-GLFW_DEPTH_BITS             = 0x00021005
-GLFW_STENCIL_BITS           = 0x00021006
-GLFW_ACCUM_RED_BITS         = 0x00021007
-GLFW_ACCUM_GREEN_BITS       = 0x00021008
-GLFW_ACCUM_BLUE_BITS        = 0x00021009
-GLFW_ACCUM_ALPHA_BITS       = 0x0002100A
-GLFW_AUX_BUFFERS            = 0x0002100B
-GLFW_STEREO                 = 0x0002100C
-GLFW_SAMPLES                = 0x0002100D
-GLFW_SRGB_CAPABLE           = 0x0002100E
-GLFW_REFRESH_RATE           = 0x0002100F
-
-# ---
-GLFW_CLIENT_API             = 0x00022001
-GLFW_CONTEXT_VERSION_MAJOR  = 0x00022002
-GLFW_CONTEXT_VERSION_MINOR  = 0x00022003
-GLFW_CONTEXT_REVISION       = 0x00022004
-GLFW_CONTEXT_ROBUSTNESS     = 0x00022005
-GLFW_OPENGL_FORWARD_COMPAT  = 0x00022006
-GLFW_OPENGL_DEBUG_CONTEXT   = 0x00022007
-GLFW_OPENGL_PROFILE         = 0x00022008
-
-# ---
-GLFW_OPENGL_API             = 0x00030001
-GLFW_OPENGL_ES_API          = 0x00030002
-
-# ---
-GLFW_NO_ROBUSTNESS          =          0
-GLFW_NO_RESET_NOTIFICATION  = 0x00031001
-GLFW_LOSE_CONTEXT_ON_RESET  = 0x00031002
-
-# ---
-GLFW_OPENGL_ANY_PROFILE     =          0
-GLFW_OPENGL_CORE_PROFILE    = 0x00032001
-GLFW_OPENGL_COMPAT_PROFILE  = 0x00032002
-
-# ---
-GLFW_CURSOR                 = 0x00033001
-GLFW_STICKY_KEYS            = 0x00033002
-GLFW_STICKY_MOUSE_BUTTONS   = 0x00033003
-
-# ---
-GLFW_CURSOR_NORMAL          = 0x00034001
-GLFW_CURSOR_HIDDEN          = 0x00034002
-GLFW_CURSOR_DISABLED        = 0x00034003
-
-# ---
-GLFW_CONNECTED              = 0x00040001
-GLFW_DISCONNECTED           = 0x00040002
-
-
-# --- Structures --------------------------------------------------------------
-class GLFWvidmode(Structure):
-    _fields_ = [ ('width',       c_int),
-                 ('height',      c_int),
-                 ('redBits',     c_int),
-                 ('greenBits',   c_int),
-                 ('blueBits',    c_int),
-                 ('refreshRate', c_int) ]
-
-class GLFWgammaramp(Structure):
-    _fields_ = [ ('red',     POINTER(c_ushort)),
-                 ('green',   POINTER(c_ushort)),
-                 ('blue',    POINTER(c_ushort)),
-                 ('size',    c_int) ]
-
-class GLFWwindow(Structure): pass
-class GLFWmonitor(Structure): pass
-
-# --- Callbacks ---------------------------------------------------------------
-errorfun           = CFUNCTYPE(None, c_int, c_char_p)
-windowposfun       = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
-windowsizefun      = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
-windowclosefun     = CFUNCTYPE(None, POINTER(GLFWwindow))
-windowrefreshfun   = CFUNCTYPE(None, POINTER(GLFWwindow))
-windowfocusfun     = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
-windowiconifyfun   = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
-framebuffersizefun = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int)
-mousebuttonfun     = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int)
-cursorposfun       = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
-cursorenterfun     = CFUNCTYPE(None, POINTER(GLFWwindow), c_int)
-scrollfun          = CFUNCTYPE(None, POINTER(GLFWwindow), c_double, c_double)
-keyfun             = CFUNCTYPE(None, POINTER(GLFWwindow), c_int, c_int, c_int, c_int)
-charfun            = CFUNCTYPE(None, POINTER(GLFWwindow), c_uint)
-monitorfun         = CFUNCTYPE(None, POINTER(GLFWmonitor), c_int)
-
-# --- Init --------------------------------------------------------------------
-glfwInit                        = _glfw.glfwInit
-glfwTerminate                   = _glfw.glfwTerminate
-#glfwGetVersion                 = _glfw.glfwGetVersion
-
-# --- Error -------------------------------------------------------------------
-#glfwSetErrorCallback            = _glfw.glfwSetErrorCallback
-
-# --- Monitor -----------------------------------------------------------------
-# glfwGetMonitors                 = _glfw.glfwGetMonitors
-# glfwGetMonitors.restype         = POINTER(GLFWmonitor)
-glfwGetPrimaryMonitor           = _glfw.glfwGetPrimaryMonitor
-# glfwGetMonitorPos               = _glfw.glfwGetMonitorPos
-# glfwGetMonitorPhysicalSize      = _glfw.glfwGetMonitorPhysicalSize
-glfwGetMonitorName              = _glfw.glfwGetMonitorName
-glfwGetMonitorName.restype = c_char_p
-# glfwSetMonitorCallback          = _glfw.glfwSetMonitorCallback
-# glfwGetVideoModes               = _glfw.glfwGetVideoModes
-# glfwGetVideoMode                = _glfw.glfwGetVideoMode
-
-# --- Gama --------------------------------------------------------------------
-glfwSetGamma                   = _glfw.glfwSetGamma
-# glfwGetGammaRamp               = _glfw.glfwGetGammaRamp
-# glfwSetGammaRamp               = _glfw.glfwSetGammaRamp
-
-# --- Window ------------------------------------------------------------------
-glfwDefaultWindowHints         = _glfw.glfwDefaultWindowHints
-glfwWindowHint                 = _glfw.glfwWindowHint
-# glfwCreateWindow              = _glfw.glfwCreateWindow
-# glfwDestroyWindow              = _glfw.glfwDestroyWindow
-glfwWindowShouldClose          = _glfw.glfwWindowShouldClose
-glfwSetWindowShouldClose       = _glfw.glfwSetWindowShouldClose
-glfwSetWindowTitle             = _glfw.glfwSetWindowTitle
-# glfwGetWindowPos              = _glfw.glfwGetWindowPos
-glfwSetWindowPos               = _glfw.glfwSetWindowPos
-# glfwGetWindowSize             = _glfw.glfwGetWindowSize
-glfwSetWindowSize              = _glfw.glfwSetWindowSize
-# glfwGetFramebufferSize        = _glfw.glfwGetFramebufferSize
-glfwIconifyWindow              = _glfw.glfwIconifyWindow
-glfwRestoreWindow              = _glfw.glfwRestoreWindow
-glfwShowWindow                 = _glfw.glfwShowWindow
-glfwHideWindow                 = _glfw.glfwHideWindow
-glfwGetWindowMonitor           = _glfw.glfwGetWindowMonitor
-glfwGetWindowAttrib            = _glfw.glfwGetWindowAttrib
-glfwSetWindowUserPointer       = _glfw.glfwSetWindowUserPointer
-glfwGetWindowUserPointer       = _glfw.glfwGetWindowUserPointer
-# glfwSetWindowPosCallback       = _glfw.glfwSetWindowPosCallback
-# glfwSetWindowSizeCallback      = _glfw.glfwSetWindowSizeCallback
-# glfwSetWindowCloseCallback     = _glfw.glfwSetWindowCloseCallback
-# glfwSetWindowRefreshCallback   = _glfw.glfwSetWindowRefreshCallback
-# glfwSetWindowFocusCallback     = _glfw.glfwSetWindowFocusCallback
-# glfwSetWindowIconifyCallback   = _glfw.glfwSetWindowIconifyCallback
-# glfwSetFramebufferSizeCallback = _glfw.glfwSetFramebufferSizeCallback
-glfwPollEvents                 = _glfw.glfwPollEvents
-glfwWaitEvents                 = _glfw.glfwWaitEvents
-
-# --- Input -------------------------------------------------------------------
-glfwGetInputMode               = _glfw.glfwGetInputMode
-glfwSetInputMode               = _glfw.glfwSetInputMode
-glfwGetKey                     = _glfw.glfwGetKey
-glfwGetMouseButton             = _glfw.glfwGetMouseButton
-# glfwGetCursorPos               = _glfw.glfwGetCursorPos
-glfwSetCursorPos               = _glfw.glfwSetCursorPos
-# glfwSetKeyCallback             = _glfw.glfwSetKeyCallback
-# glfwSetCharCallback            = _glfw.glfwSetCharCallback
-# glfwSetMouseButtonCallback     = _glfw.glfwSetMouseButtonCallback
-# glfwSetCursorPosCallback       = _glfw.glfwSetCursorPosCallback
-# glfwSetCursorEnterCallback     = _glfw.glfwSetCursorEnterCallback
-# glfwSetScrollCallback          = _glfw.glfwSetScrollCallback
-glfwJoystickPresent            = _glfw.glfwJoystickPresent
-# glfwGetJoystickAxes            = _glfw.glfwGetJoystickAxes
-# glfwGetJoystickButtons         = _glfw.glfwGetJoystickButtons
-glfwGetJoystickName            = _glfw.glfwGetJoystickName
-glfwGetJoystickName.restype = c_char_p
-
-# --- Clipboard ---------------------------------------------------------------
-glfwSetClipboardString         = _glfw.glfwSetClipboardString
-glfwGetClipboardString         = _glfw.glfwGetClipboardString
-glfwGetClipboardString.restype = c_char_p
-
-# --- Timer -------------------------------------------------------------------
-glfwGetTime                    = _glfw.glfwGetTime
-glfwGetTime.restype = c_double
-glfwSetTime                    = _glfw.glfwSetTime
-
-# --- Context -----------------------------------------------------------------
-glfwMakeContextCurrent         = _glfw.glfwMakeContextCurrent
-glfwGetCurrentContext          = _glfw.glfwGetCurrentContext
-glfwSwapBuffers                = _glfw.glfwSwapBuffers
-glfwSwapInterval               = _glfw.glfwSwapInterval
-glfwExtensionSupported         = _glfw.glfwExtensionSupported
-glfwGetProcAddress             = _glfw.glfwGetProcAddress
-
-
-
-# --- Pythonizer --------------------------------------------------------------
-
-# This keeps track of current windows
-__windows__ = []
-__destroyed__ = []
-
-# This is to prevent garbage collection on callbacks
-__c_callbacks__ = {}
-__py_callbacks__ = {}
-__c_error_callback__ = None
-
-def glfwCreateWindow(width=640, height=480, title="GLFW Window",
-                     monitor=None, share=None):
-    _glfw.glfwCreateWindow.restype = POINTER(GLFWwindow)
-    window = _glfw.glfwCreateWindow(int(width), int(height),
-                                    title.encode('utf-8'), monitor, share)
-    __windows__.append(window)
-    __destroyed__.append(False)
-    index = __windows__.index(window)
-    __c_callbacks__[index] = {}
-    __py_callbacks__[index] = { 'errorfun'           : None,
-                                'monitorfun'         : None,
-                                'windowposfun'       : None,
-                                'windowsizefun'      : None,
-                                'windowclosefun'     : None,
-                                'windowrefreshfun'   : None,
-                                'windowfocusfun'     : None,
-                                'windowiconifyfun'   : None,
-                                'framebuffersizefun' : None,
-                                'keyfun'             : None,
-                                'charfun'            : None,
-                                'mousebuttonfun'     : None,
-                                'cursorposfun'       : None,
-                                'cursorenterfun'     : None,
-                                'scrollfun'          : None }
-    return window
-
-
-def glfwDestroyWindow(window):
-    index = __windows__.index(window)
-    if not __destroyed__[index]:
-        # We do not delete window from the list (or it would impact numbering)
-        __windows__[index] = None
-        _glfw.glfwDestroyWindow(window)
-        del __c_callbacks__[index]
-        del __py_callbacks__[index]
-    __destroyed__[index] = True
-
-
-def glfwGetWindowPos(window):
-    xpos, ypos = c_int(0), c_int(0)
-    _glfw.glfwGetWindowPos(window, byref(xpos), byref(ypos))
-    return xpos.value, ypos.value
-
-
-def glfwGetCursorPos(window):
-    xpos, ypos = c_double(0), c_double(0)
-    _glfw.glfwGetCursorPos(window, byref(xpos), byref(ypos))
-    return int(xpos.value), int(ypos.value)
-
-
-def glfwGetWindowSize(window):
-    width, height = c_int(0), c_int(0)
-    _glfw.glfwGetWindowSize(window, byref(width), byref(height))
-    return width.value, height.value
-
-
-def glfwGetFramebufferSize(window):
-    width, height = c_int(0), c_int(0)
-    _glfw.glfwGetFramebufferSize(window, byref(width), byref(height))
-    return width.value, height.value
-
-
-def glfwGetMonitors():
-    count = c_int(0)
-    _glfw.glfwGetMonitors.restype = POINTER(POINTER(GLFWmonitor))
-    c_monitors = _glfw.glfwGetMonitors( byref(count) )
-    return [c_monitors[i] for i in range(count.value)]
-
-
-def glfwGetVideoModes(monitor):
-    count = c_int(0)
-    _glfw.glfwGetVideoModes.restype = POINTER(GLFWvidmode)
-    c_modes = _glfw.glfwGetVideoModes( monitor, byref(count) )
-    modes = []
-    for i in range(count.value):
-        modes.append( (c_modes[i].width,
-                       c_modes[i].height,
-                       c_modes[i].redBits,
-                       c_modes[i].blueBits,
-                       c_modes[i].greenBits,
-                       c_modes[i].refreshRate ) )
-    return modes
-
-
-def glfwGetMonitorPos(monitor):
-    xpos, ypos = c_int(0), c_int(0)
-    _glfw.glfwGetMonitorPos(monitor, byref(xpos), byref(ypos))
-    return xpos.value, ypos.value
-
-
-def glfwGetMonitorPhysicalSize(monitor):
-    width, height = c_int(0), c_int(0)
-    _glfw.glfwGetMonitorPhysicalSize(monitor, byref(width), byref(height))
-    return width.value, height.value
-
-
-def glfwGetVideoMode(monitor):
-    _glfw.glfwGetVideoMode.restype = POINTER(GLFWvidmode)
-    c_mode = _glfw.glfwGetVideoMode(monitor).contents
-    return (c_mode.width,
-            c_mode.height,
-            c_mode.redBits,
-            c_mode.blueBits,
-            c_mode.greenBits,
-            c_mode.refreshRate )
-
-
-def GetGammaRamp(monitor):
-    _glfw.glfwGetGammaRamp.restype = POINTER(GLFWgammaramp)
-    c_gamma = _glfw.glfwGetGammaRamp(monitor).contents
-    gamma = {'red':[], 'green':[], 'blue':[]}
-    if c_gamma:
-        for i in range(c_gamma.size):
-            gamma['red'].append(c_gamma.red[i])
-            gamma['green'].append(c_gamma.green[i])
-            gamma['blue'].append(c_gamma.blue[i])
-    return gamma
-
-
-def glfwGetJoystickAxes(joy):
-    count = c_int(0)
-    _glfw.glfwGetJoystickAxes.restype = POINTER(c_float)
-    c_axes = _glfw.glfwGetJoystickAxes(joy, byref(count))
-    axes = [c_axes[i].value for i in range(count)]
-    return axes
-
-
-def glfwGetJoystickButtons(joy):
-    count = c_int(0)
-    _glfw.glfwGetJoystickButtons.restype = POINTER(c_int)
-    c_buttons = _glfw.glfwGetJoystickButtons(joy, byref(count))
-    buttons = [c_buttons[i].value for i in range(count)]
-    return buttons
-
-
-# --- Callbacks ---------------------------------------------------------------
-
-def __callback__(name):
-    callback = 'glfwSet%sCallback' % name
-    fun      = '%sfun' % name.lower()
-    code = """
-def %(callback)s(window, callback = None):
-    index = __windows__.index(window)
-    old_callback = __py_callbacks__[index]['%(fun)s']
-    __py_callbacks__[index]['%(fun)s'] = callback
-    if callback: callback = %(fun)s(callback)
-    __c_callbacks__[index]['%(fun)s'] = callback
-    _glfw.%(callback)s(window, callback)
-    return old_callback""" % {'callback': callback, 'fun': fun}
-    return code
-
-exec(__callback__('Monitor'))
-exec(__callback__('WindowPos'))
-exec(__callback__('WindowSize'))
-exec(__callback__('WindowClose'))
-exec(__callback__('WindowRefresh'))
-exec(__callback__('WindowFocus'))
-exec(__callback__('WindowIconify'))
-exec(__callback__('FramebufferSize'))
-exec(__callback__('Key'))
-exec(__callback__('Char'))
-exec(__callback__('MouseButton'))
-exec(__callback__('CursorPos'))
-exec(__callback__('Scroll'))
-
-
-# Error callback does not take window parameter
-def glfwSetErrorCallback(callback = None):
-    global __c_error_callback__
-    __c_error_callback__ = errorfun(callback)
-    _glfw.glfwSetErrorCallback(__c_error_callback__)
\ No newline at end of file


Test patch: