florianrhiem / pyglfw Goto Github PK
View Code? Open in Web Editor NEWPython bindings for GLFW
License: MIT License
Python bindings for GLFW
License: MIT License
I fixed this on my fork please merge.
Is there any way to set glfw in way that glfw.init() pop up the new window in the background and does not make it the active window.
Hey! we're building a Python wrapper around the wgpu lib, and would like to use glfw as a lightweight alternative to provide a window.
However, to make things work, I need to provide wgpu with a native window id so it can create a surface object. It looks like glfw in principal supports this via e.g. glfwGetWin32Window.
Any idea how feasible it is to expose this via the Python API?
Thanks!
Could you please consider to add it to pypi release tarball?
Feels like I'm missing something obvious here, but how do I get the pointer value that I'd pass to some other library wanting a GLFWwindow*?
Fails to find GLFW on Mac M1:
Traceback (most recent call last):
File "/Users/junglie85/Personal/pygraphics/main.py", line 1, in <module>
import glfw
File "/Users/junglie85/Personal/pygraphics/venv/lib/python3.9/site-packages/glfw/__init__.py", line 43, in <module>
raise ImportError("Failed to load GLFW3 shared library.")
ImportError: Failed to load GLFW3 shared library.
Also cannot load manually installed GLFW PYGLFW_LIBRARY=/opt/homebrew/Cellar/glfw/3.3.4
.
Thank for creating this library. ๐
We're using it now in:
pyGLFW seems to perform quite well compated to PyQt5, so it's important to have alternatives.
GLFW_DOUBLEBUFFER should be set to 0x00021010 according to the glfw3.h header at
https://github.com/glfw/glfw/blob/master/include/GLFW/glfw3.h#L646
But I don't see the GLFW_DOUBLEBUFFER symbol anywhere in https://github.com/FlorianRhiem/pyGLFW/blob/master/glfw.py
For the time being I am setting the value locally in my application as a workaround.
According to GLFW developer @elmindreda (see glfw/glfw#1121 (comment)) errors in GLFW are not critical (as in halting the execution of the program). In pyGLFW the default behaviour is the opposite (halting execution on all errors). This makes for a bad developer experience and breaks wayland support (see mentioned issue request)
Therefore I propose to change:
ERROR_REPORTING = True
To
ERROR_REPORTING = "warn"
Currently, the Linux wheels are built on the manylinux2010
image with a few more X11-related libraries (libXinerama, libXrandr, libXcursor and libXi). This works well for X11 users, but on Wayland users still need to install the GLFW shared library themselves. Ideally, the Linux wheels would allow users of both X11 and Wayland to run GLFW without installing additional packages.
As far as I know, the wheel platform tags are all for X11 based systems so far. I'm not aware of any Wayland support for CentOS 6, which manylinux2010
is based on. manylinux2014
is based on CentOS 7, which seems to have some Wayland support, though it's not the default.
I meant to test out the latest version on Linux (Ubuntu 19.10), because I suspected there might be an issue on Wayland, but ran into an issue. pip install glfw
will take the tar.gz
instead of the wheel. Pointing pip directly at the wheel gives me glfw-1.10.1-py2.py3-none-manylinux2010_x86_64.whl is not a supported wheel on this platform
. So it looks like there's a flag somewhere there that prevents it from being used. I tried with pip 18.x and 20.0.1. Have you looked at auditwheel
to verify/repair these wheels?
edit: the below turns out not to be an issue
I could therefore not test the potential issue I was looking into, so I'll just describe it. I can have a look later if needed. If the binary glfw lib that comes packaged is preferred over the system library, it will probably fail on Wayland (because it needs a differently compiled lib). The user can of course use PYGLFW_LIBRARY
but that's annoying.
The README
says that you can use the system library by installing it, but library.py seems to prefer the packaged lib instead, but I may be wrong here.
None of these are pressing issues, BTW :)
Using your API changes the current working directory. So i had problems including my shaders with relative path.
I can't seem to get window hints to work. The following produces a window that can be resized and is visible. Any idea on how I can get this to work? Primary goal is to get the OpenGL stuff working on the core profile but can't seem to get it to work.
Mac 10.13 High Sierra
import glfw
def main():
if not glfw.init():
exit()
window = glfw.create_window(640, 480, "HELLO WORLD", None, None)
if not window:
glfw.terminate()
exit()
glfw.window_hint(glfw.RESIZABLE, False)
glfw.window_hint(glfw.VISIBLE, False)
#glfw.WindowHint(glfw.CONTEXT_VERSION_MAJOR, 3)
#glfw.WindowHint(glfw.CONTEXT_VERSION_MINOR, 3)
#glfw.WindowHint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
#glfw.WindowHint(glfw.OPENGL_FORWARD_COMPAT, True)
glfw.make_context_current(window)
while not glfw.window_should_close(window):
glfw.swap_interval(1)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
main()
glfw.py, line 140: add this:
if _glfw is None:
_glfw = ctypes.CDLL("glfw3.dll")
I can't make much sense of the detection code that's there. It looks like it should pick up a .dll, but it didn't.
I was trying to disable the feature which moves the cursor to the center of a newly created fullscreen window by setting the GLFW_CENTER_CURSOR window hint (glfw.CENTER_CURSOR for this package). This returns the following error when glfw.create_window is called:
Traceback (most recent call last): File "d:/Alejandro/HSCDMV2/Test-Codes/glfwbug.py", line 5, in <module> glfw.window_hint(glfw.CENTER_CURSOR, glfw.FALSE) File "C:\Users\shilab\AppData\Local\Programs\Python\Python37\lib\site-packages\glfw\__init__.py", line 1110, in window_hint _glfw.glfwWindowHint(hint, value) File "C:\Users\shilab\AppData\Local\Programs\Python\Python37\lib\site-packages\glfw\__init__.py", line 609, in errcheck _reraise(exc[1], exc[2]) File "C:\Users\shilab\AppData\Local\Programs\Python\Python37\lib\site-packages\glfw\__init__.py", line 45, in _reraise raise exception.with_traceback(traceback) File "C:\Users\shilab\AppData\Local\Programs\Python\Python37\lib\site-packages\glfw\__init__.py", line 588, in callback_wrapper return func(*args, **kwargs) File "C:\Users\shilab\AppData\Local\Programs\Python\Python37\lib\site-packages\glfw\__init__.py", line 800, in _raise_glfw_errors_as_exceptions raise GLFWError(message) glfw.GLFWError: (65539) b'Invalid window hint 131081'
Below is a code which reproduces the issue on my machine:
The readme says that Linux users must compile GLFW from source, which might put people off. At least on Ubuntu it's just apt install libglfw3
(or libglfw3-wayland
).
While using the package in an anaconda environment (pip installed the glfw package into anacona env), I ran into an issue where ctypes.CDLL wouldn't load the bundled dll.
Downloading the glfw3 official precompiled binaries and replacing the bundled binary with the 64 bit lib-vc2015 build (my system specifics) eventually solved the problem, but I'm raising the issue so that if others run into this kind of problem, they may have a shortcut.
Or maybe there's a convenient solution to this, I'm not sure :)
Thanks anyways!
Error:
File "C:\Users\huml-dkn\Desktop\F95Checker\venv\lib\site-packages\glfw\__init__.py", line 1090, in set_monitor_user_pointer
_monitor_user_data_repository[monitor] = data
TypeError: unhashable type
Needs something similar like set_window_user_pointer
monitor_addr = ctypes.cast(ctypes.pointer(monitor), ctypes.POINTER(ctypes.c_long)).contents.value
same for get_monitor_user_pointer
i am writing a vulkan application and when wanting to create the window it tells me
glfw.GLFWError: (65539) b'Invalid client API'
i have set the CLIENT_API
to NO_API
but somehow it throws an error and i dont know why
I downloaded glfw-1.8.5-py2.py3-none-win32.zip
and glfw-1.8.5-py2.py3-none-win_amd64.zip
from pypi and unzipped them:
md5 glfw-win*/glfw3.dll
MD5 (glfw-win32/glfw3.dll) = cc96a6eed5b83cc4521a16499ddf7187
MD5 (glfw-win_amd64/glfw3.dll) = cc96a6eed5b83cc4521a16499ddf7187
It looks like the packaging is messed up and that these are both the 32 bit dll, any ideas?
MD5 (glfw-3.3.bin.WIN32/lib-vc2010/glfw3.dll) = cc96a6eed5b83cc4521a16499ddf7187
Hi,
I used to render to frame buffer object images with width< 1061 using this code:
glfw.init()
glfw.window_hint(glfw.VISIBLE, False)
self.window = glfw.create_window(self.width, self.height, "My OpenGL window", None, None)
glfw.make_context_current(self.window)
And that work fine. For example, if I used: glGetDoublev(GL_VIEWPORT) I will get:
array([ 0., 0., 1300., 1000.])
But when I try to use the same code for an image with a width larger then 1061 I get:
array([ 0., 0., 1300., 1061.])
I am using windows PyOpenGL and PyGlfw.
Thanks,
Avi
I'm trying to set my main loop rate to my monitor refresh rate for more control:
...
mon = GLFW.get_primary_monitor()
mode = mon.video_mode
size, bits, refresh_rate = mode
...
while not win.should_close:
GLFW.poll_events()
_display(W,H)
win.swap_buffers()
time.sleep(1./refresh_rate)
swap interval is not guaranteed at 75Hz
When using Windows' print screen functionality (Print Screen, Win + Print Screen, Alt + Print Screen), only the very first rendered frame is captured. This only seems to happen in full screen mode and not in windowed mode.
I've been asking around and might be related to double/triple buffering on the driver side of things. Not sure if anything can be done about this?
Installing glfw on Linux AArch64 machine using command python -m pip install glfw
, downloads the source distribution and build/install it. This installation results in missing X11 and Wayland libraries.
@FlorianRhiem and team, can you please let me know your thoughts on release Linux AArch64 wheels on PyPI?
In Python 3.4 glfw.py[130]: out = process.communicate(_to_char_p(filename))[0]
fails with TypeError: must be str, not bytes
As far as I can tell, when universal_newlines=True
is set in the previous line it tells subprocess
to use
type _io.TextIOWrapper
for stdin
. TextIOWrapper
expects string input, not bytes:
All streams are careful about the type of data you give to them. For example giving a str object to the write() method of a binary stream will raise a TypeError. So will giving a bytes object to the write() method of a text stream.
I can get around the problem by scrapping the use of the _to_char_p
lambda and just passing the string filename.
References:
This is the code section that needs changing.
Not 100% sure if it is as simple as passing None
instead of a window reference.
Does setting this env var mean that pyglfw automatically clones the latest code from glfw and builds it?
Or is the glfw version compiled by you (@FlorianRhiem I'd assume) at some point?
Hi Florian,
Using pyGLFW 1.11 on Wayland I get the following message when creating a window:
...
File "/home/aanjos/.local/lib/python3.8/site-packages/glfw/__init__.py", line 1156, in create_window
return _glfw.glfwCreateWindow(width, height, _to_char_p(title),
File "/home/aanjos/.local/lib/python3.8/site-packages/glfw/__init__.py", line 616, in errcheck
_reraise(exc[1], exc[2])
File "/home/aanjos/.local/lib/python3.8/site-packages/glfw/__init__.py", line 52, in _reraise
raise exception.with_traceback(traceback)
File "/home/aanjos/.local/lib/python3.8/site-packages/glfw/__init__.py", line 595, in callback_wrapper
return func(*args, **kwargs)
File "/home/aanjos/.local/lib/python3.8/site-packages/glfw/__init__.py", line 808, in _handle_glfw_errors
raise GLFWError(message)
glfw.GLFWError: (65544) b'Wayland: Focusing a window requires user interaction'
I've tried the "fix" I've found on one of the solved issues:
if sys.platform.startswith("linux"):
if "wayland" in os.getenv("XDG_SESSION_TYPE", "").lower():
glfw.window_hint(glfw.FOCUSED, False)
However, I get the following:
File "/home/aanjos/Documents/git_sandbox/g3D/g3D/Drawable.py", line 36, in vbo_vertex_data
gl.glVertexAttribPointer(layout_pos, 3, gl.GL_FLOAT, False, 0, None)
File "/home/aanjos/.local/lib/python3.8/site-packages/OpenGL/latebind.py", line 63, in __call__
return self.wrapperFunction( self.baseFunction, *args, **named )
File "/home/aanjos/.local/lib/python3.8/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 469, in glVertexAttribPointer
contextdata.setValue( key, array )
File "/home/aanjos/.local/lib/python3.8/site-packages/OpenGL/contextdata.py", line 58, in setValue
context = getContext( context )
File "/home/aanjos/.local/lib/python3.8/site-packages/OpenGL/contextdata.py", line 40, in getContext
raise error.Error(Error: Attempt to retrieve context when no valid context
Everything was working on Ubuntu 20.04. I've installed Debian testing today because it has the Linux kernel 5.5 and I got this problem.
I have libgfw3-wayland 3.3.2-1.
Thanks,
Antรณnio
Whatever version I set, the command glfw.get_version_string()
always returns version:b'3.3.5 Win32 WGL EGL OSMesa VisualC DLL'
. Is it a bug?
The demo below shows that it always prints OpenGL version: b'3.3.5 Win32 WGL EGL OSMesa VisualC DLL'
import glfw
from OpenGL.GL import *
# initializing glfw library
if not glfw.init():
raise Exception("glfw can not be initialized!")
# Configure the OpenGL context.
# If we are planning to use anything above 2.1 we must at least
# request a 3.3 core context to make this work across platforms.
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 4)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 0)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, True)
# 4 MSAA is a good default with wide support
glfw.window_hint(glfw.SAMPLES, 4)
# creating the window
window = glfw.create_window(1280, 720, "My OpenGL window", None, None)
# check if window was created
if not window:
glfw.terminate()
raise Exception("glfw window can not be created!")
# Query the actual framebuffer size so we can set the right viewport later
# -> glViewport(0, 0, framebuffer_size[0], framebuffer_size[1])
framebuffer_size = glfw.get_framebuffer_size(window)
# set window's position
glfw.set_window_pos(window, 400, 200)
# make the context current
glfw.make_context_current(window)
version = glfw.get_version_string()
print(f"OpenGL version:{version}")
# the main application loop
while not glfw.window_should_close(window):
glfw.poll_events()
glfw.swap_buffers(window)
# terminate glfw, free up allocated resources
glfw.terminate()
This is with pyglfw 1.3.3 on Linux. The _load_library call in glfw.py uses a fixed set of paths that it searches for the GLFW shared lib. Unfortunately, I don't have GLFW3 installed system-wide as the available Debian package on jessie is a bit old. So I compiled and installed the latest GLFW3 in a custom location (/software/glfw/3.2.1 in this case), but I can't direct pyglfw to get the shared lib from there without hacking glfw.py.
Here's an updated excerpt of glfw.py, starting around line 150, to make it search the paths in LD_LIBRARY_PATH as well:
if sys.platform == 'win32':
# only try glfw3.dll on windows
try:
_glfw = ctypes.CDLL('glfw3.dll')
except OSError:
_glfw = None
else:
search_paths = [
'',
'/usr/lib64', '/usr/local/lib64',
'/usr/lib', '/usr/local/lib',
'/run/current-system/sw/lib',
'/usr/lib/x86_64-linux-gnu/'
]
if 'LD_LIBRARY_PATH' in os.environ:
search_paths.extend(os.environ['LD_LIBRARY_PATH'].split(':'))
_glfw = _load_library(['glfw', 'glfw3'], ['.so', '.dylib'],
search_paths, _glfw_get_version)
When I try to import pyGLFW, the import fails in "subprocess.py" because it tries to use encode on a bytes-type object. This does not happen in Python 2.7.5 on the same machine.
Python 3.3.2 (default, Jun 30 2014, 17:20:03)
[GCC 4.8.3 20140624 (Red Hat 4.8.3-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
import glfw
Traceback (most recent call last):
File "", line 1, in
File "/usr/lib/python3.3/site-packages/glfw.py", line 138, in
['', '/usr/lib', '/usr/local/lib'], _glfw_get_version)
File "/usr/lib/python3.3/site-packages/glfw.py", line 74, in _load_library
version = version_check_callback(filename)
File "/usr/lib/python3.3/site-packages/glfw.py", line 130, in _glfw_get_version
out = process.communicate(_to_char_p(filename))[0]
File "/usr/lib64/python3.3/subprocess.py", line 922, in communicate
stdout, stderr = self._communicate(input, endtime, timeout)
File "/usr/lib64/python3.3/subprocess.py", line 1546, in _communicate
orig_timeout)
File "/usr/lib64/python3.3/subprocess.py", line 1619, in _communicate_with_poll
self._save_input(input)
File "/usr/lib64/python3.3/subprocess.py", line 1580, in _save_input
self._input = self._input.encode(self.stdin.encoding)
AttributeError: 'bytes' object has no attribute 'encode'
GLFW 3.3 was released last week. I won't have time to work on this until mid may, but after that I will start adding the missing functions and constants.
Hi, I'm getting the following error when calling glfwGetMonitorContentScale
:
... (traceback in my code) ...
File "/home/pfa/.pyenv/versions/3.6.9/lib/python3.6/site-packages/glfw/__init__.py", line 937, in get_monitor_content_scale
_glfw.glfwGetMonitorContentScale(monitor, xscale, yscale)
ctypes.ArgumentError: argument 2: <class 'TypeError'>: expected LP_c_float instance instead of LP_c_int
It seems that pyGLFW is trying to call the ctypes function with ints, but glfwGetMonitorContentScale requires floats: https://www.glfw.org/docs/latest/group__monitor.html#gad3152e84465fa620b601265ebfcdb21b
Im using GLFW 3.3 and pyGLFW 1.8.6 on Ubuntu 18.04.
Hello, could you please publish the source distribution of v1.9.0 on PyPI as well? Thank you very much!
Getting error when trying to call glfw.set_window_opacity. Here is the traceback significant part ->
File "/home/roni/.pyenv/versions/3.8.3/lib/python3.8/site-packages/glfw/init.py", line 1337, in set_window_opacity
_glfw.glfwSetWindowOpacity(window)
TypeError: this function takes at least 2 arguments (1 given)
Maybe the second param was missed somehow.
I fixed it with passing the second param manually and it works.
I don't see the wrapper for this in any of the branches and when I tried glfw.gl_viewport(0, 0, 640, 480)
my program crashes to an AttributeError: module 'glfw' has no attribute 'gl_viewport'
Im following a very simple code example to draw something on screen using glfw and opengl but I get met with
Traceback (most recent call last):
File "/home/nanyo/Documents/ProgrammingEnvs/PythonEnvs/pyVisuals/src/__unused/test.py", line 75, in <module>
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, ctypes.c_void_p(0))
File "/home/nanyo/Documents/ProgrammingEnvs/PythonEnvs/pyVisuals/lib/python3.10/site-packages/OpenGL/latebind.py", line 63, in __call__
return self.wrapperFunction( self.baseFunction, *args, **named )
File "/home/nanyo/Documents/ProgrammingEnvs/PythonEnvs/pyVisuals/lib/python3.10/site-packages/OpenGL/GL/VERSION/GL_2_0.py", line 469, in glVertexAttribPointer
contextdata.setValue( key, array )
File "/home/nanyo/Documents/ProgrammingEnvs/PythonEnvs/pyVisuals/lib/python3.10/site-packages/OpenGL/contextdata.py", line 58, in setValue
context = getContext( context )
File "/home/nanyo/Documents/ProgrammingEnvs/PythonEnvs/pyVisuals/lib/python3.10/site-packages/OpenGL/contextdata.py", line 40, in getContext
raise error.Error(
OpenGL.error.Error: Attempt to retrieve context when no valid context
I have reduced my code as much as possible so I can post it here, I am doing glfw.make_context_current(window)
to make the context current so I am not sure what is going wrong:
import glfw
from OpenGL.GL import *
import numpy as np
glfw.init()
glfw.window_hint(glfw.FOCUSED, glfw.FALSE)
window = glfw.create_window(640, 400, "Window", None, None)
glfw.make_context_current(window)
vertices = [
0.5, 0.5, 0.0,
0.5, -0.5, 0.0,
-0.5, -0.5, 0.0,
-0.5, 0.5, 0.0
]
indices = [
0, 1, 3,
1, 2, 3
]
vertices = np.array(vertices, dtype=np.float32)
indices = np.array(indices, dtype=np.int32)
vertex_shader_source = """
#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
"""
frag_shader_source = """
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
"""
vertex_shader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertex_shader, [vertex_shader_source])
glCompileShader(vertex_shader)
print(glGetShaderiv(vertex_shader, GL_COMPILE_STATUS))
frag_shader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(frag_shader, [frag_shader_source])
glCompileShader(frag_shader)
print(glGetShaderiv(frag_shader, GL_COMPILE_STATUS))
shader_program = glCreateProgram()
glAttachShader(shader_program, vertex_shader)
glAttachShader(shader_program, frag_shader)
glLinkProgram(shader_program)
print(glGetProgramiv(shader_program, GL_LINK_STATUS))
glDeleteShader(vertex_shader)
glDeleteShader(frag_shader)
VAO = glGenVertexArrays(1)
VBO = glGenBuffers(1)
EBO = glGenBuffers(1)
glBindVertexArray(VAO)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glClearColor(1, 0, 0, 1)
while not glfw.window_should_close(window):
glClear(GL_COLOR_BUFFER_BIT)
glUseProgram(shader_program)
glBindVertexArray(VAO)
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
Putting:
print(glfw.get_current_context())
just before:
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 12, ctypes.c_void_p(0))
prints <glfw.LP__GLFWwindow object at 0x7f822c987340>
meaning that some context was created for that window, as far as I understand the glfw docs.
EDIT: might be worth mentioning that I compiled glfw from source and replaced the wheel package with this newly compiled version as glfw 3.3.x does not work with ubuntu 21 and its wayland version
EDIT2: I am currently investigating if this has potentially something to do with my nvidia drivers and my gpu not showing up on some places as it should. Although I have an igpu capable of OpenGL 4.6 support
Hi Florian,
I just did a fork of pyGLFW where I switched all variable names from lowercase_with_underscores to camelCase (or 'mixedCase') and added the 'GLFW_' prefixes to the macros.
Even though this is not the recommended PEP8 way, in this case the camelCase approach is very helpful when you want to port C++ code to Python.
That got me thinking...
So. long story short: I would like to ask you to add support for camelCase (and the GLFW_ prefixes) alongside lowercase_with_underscores. It would only have benefits - existing code still works, porting C++ code can be done a lot quicker and pyGLFW would fit the naming scheme of the library it's most likely accompanied by -- PyOpenGL (which also uses camelCase).
Naturally, the user would have to make a from import instead.
from glfw import *
Please let me know what you think about the idea.
Thanks for your consideration and best regards,
--Zuzu_Typ--
Currently there is no way to catch errors from callbacks attached to glfw using glfw.set_*_callback
.
Consider following example:
import glfw
def error_callback(err, description):
raise RuntimeError("GLFW error (%s): %s" % (err, description))
def main():
# this will fail because glfw was not initialized yet
glfw.set_error_callback(error_callback)
try:
window = glfw.create_window(640, 480, "Hello World", None, None)
except Exception as err:
print("Exception raised: %s" % err)
exit(1)
if not window:
print("Exception not raised but window creation failed")
glfw.terminate()
return
if __name__ == "__main__":
main()
When executed it gives following output:
$ python glfwerrs.py
Traceback (most recent call last):
File "_ctypes/callbacks.c", line 314, in 'calling callback function'
File "glfwerrs.py", line 6, in error_callback
raise RuntimeError("GLFW error (%s): %s" % (err, description))
RuntimeError: GLFW error (65537): The GLFW library is not initialized
Exception not raised but window creation failed
This means that exception is raised but the only effect is that traceback is printed on standard output. Program simply continues its flow. This can be problematic in some situations. For instance if we have keyboard handler that fails at some point and it is also responsible for catching input that should close application (ESC
key) then user will find difficult to exit such program. Unexpected exceptions should be propagated in stack so would terminate application if not handled properly. For this case it is not such big issue because glfw.create_window
informs about error with output value but (as stated by GLFW docs) not all functions does that and the only way to reliably handle errors is through error callbacks.
Proper propagation of exceptions could be achieved if we provide default error callback that stores latest error state (e.g. in some global/module-level variable) and utilise ctypes' errcheck
protocol by attaching custom errcheck
function to every function in glfw._glfw
library instance.
Here is simple proof of concept of how it could work:
import glfw
_errors = [None]
def _errcheck(result, func, args):
if _errors[0] is not None:
_errors[0], error = None, _errors[0]
raise error
return result
for function in glfw._glfw.__dict__.values():
if hasattr(function, 'errcheck'):
function.errcheck = _errcheck
def error_callback(err, description):
_errors[0] = RuntimeError("GLFW error (%s): %s" % (err, description))
def main():
glfw.set_error_callback(error_callback)
window = glfw.create_window(640, 480, "Hello World", None, None)
if not window:
print("Exception not raised but window creation failed")
glfw.terminate()
return
if __name__ == "__main__":
main()
This approach also gives possibility to wrap all the errors with some custom base exception class e.g. GlfwException
or even differentiate different kind of errors with different error classe by inspecting error codes.
Above example is of course not complete because:
thread.get_ident()
as state key)I can happily provide pull request for that change but I would like first to know what do you think about that and how would you prefer to solve some issues:
glfw
API like enable_exception_propagation()
that will initialize error state structure, set default handler and attach errcheck
to each glfw._glfw
(DLL) functionerrcheck
to every library function but internally verify if error propagation was enabled (again new API function).I think also that it could be very useful to expose some more internals of above behaviour so user could easily add their own error callbacks that will still properly propagate exceptions. Maybe some decorator?
As a side note about defining opt-in mechanism: I would not recommend using environment variables for defining expected behaviour because the end-user could accidentally completely corrupt application flow if it would heavily rely on exception handling.
EDIT: I have realised that I had mixed up two different things. One thing is propagating GLFW errors as exceptions and the other thing is propagating exceptions from python input handlers (keyboard, mouse, joystick etc.). Still I think that we can solve two issues using similar approach and propagating GLFW function errors as exceptions is a good start.
In __init__.py, line 840, in set_error_callback
if previous_callback is not None and previous_callback[0] != _raise_glfw_errors_as_exceptions:
NameError: name '_raise_glfw_errors_as_exceptions' is not defined
For my use case, downgrading to version 1.9 solved it. Leaving it open here to address, so that projects that have pyglfw as a requirement (e.g. mujoco_py) are not affected downstream.
Tried this on Ubuntu 18.04, with Wayland (before logging in, select Wayland via the little menu next to the unlock button), and installing the glfw lib via sudo apt install libglfw-wayland
.
This simple example fails:
import glfw
glfw.init()
# glfw.ERROR_REPORTING = False
w = glfw.create_window(640, 480, "glfw window", None, None)
Traceback:
Traceback (most recent call last):
File "<tmp 1>", line 4, in <module>
w = glfw.create_window(640, 480, "glfw window", None, None)
File "/home/almar/.local/lib/python3.6/site-packages/glfw/__init__.py", line 1141, in create_window
monitor, share)
File "/home/almar/.local/lib/python3.6/site-packages/glfw/__init__.py", line 609, in errcheck
_reraise(exc[1], exc[2])
File "/home/almar/.local/lib/python3.6/site-packages/glfw/__init__.py", line 45, in _reraise
raise exception.with_traceback(traceback)
File "/home/almar/.local/lib/python3.6/site-packages/glfw/__init__.py", line 588, in callback_wrapper
return func(*args, **kwargs)
File "/home/almar/.local/lib/python3.6/site-packages/glfw/__init__.py", line 800, in _raise_glfw_errors_as_exceptions
raise GLFWError(message)
glfw.GLFWError: (65544) b'Wayland: Focusing a window requires user interaction'
If I uncomment the line to ignore errors, it works, except the window is undecorated.
Some context: glfw/glfw#1121 seems to suggest that the error is more of a warning? See also these.
It looks like PyGLFW checks if there are errors and raises them as Python exceptions. Perhaps there should be a filter to ignore specific exceptions like this one?
using glfw.create_window_surface
I get an error:
ctypes.ArgumentError: argument 1: <class 'TypeError'>: wrong type
argument 1 is the vulkan instance and mine was created as it should : <cdata 'struct VkInstance_T *' 0x0000022EF5F83520>
Currently, the windows version of glfw needs to have the VC redistributable installed or else it fails with an error when you attempt to use it. Would you be willing to redistribute the DLL inside the windows wheel?
For the x64 version this looks like copying msvcr110.dll
from c:\windows\system32
to the package directory, then modifying this code: https://github.com/FlorianRhiem/pyGLFW/blob/master/glfw/library.py#L161 to look something like this:
elif sys.platform == 'win32':
# try glfw3.dll using windows search paths
try:
glfw = ctypes.CDLL('glfw3.dll')
except OSError:
# try glfw3.dll in package directory
try:
glfw = ctypes.CDLL(os.path.join(os.path.abspath(os.path.dirname(__file__)), 'glfw3.dll'))
except OSError:
# try glfw3.dll with included VC redistributable
os.environ["PATH"] = os.environ["PATH"] + ";" + os.path.abspath(os.path.dirname(__file__))
try:
glfw = ctypes.CDLL('glfw3.dll')
except OSError:
glfw = None
It looks like you are explicitly allowed to redistribute the redistributable DLLs: https://docs.microsoft.com/en-us/cpp/windows/determining-which-dlls-to-redistribute?view=vs-2019
The GLFW API uses the Vulkan types VkInstance
, VkPhysicalDevice
, VkAllocationCallbacks
, VkSurfaceKHR
and VkResult
. pyGLFW wraps these types using ctypes.c_void_p
(except for VkResult
, which is wrapped as a ctypes.c_int
). To make these Vulkan types more easily usable, the corresponding types from Python Vulkan wrappers should be supported.
I'm getting a KeyError on this line:
https://github.com/FlorianRhiem/pyGLFW/blob/master/glfw.py#L809
This assumes that all windows are in all callback repositories, which I guess isn't necessarily true.
The current traceback isn't so helpful when using Python 2. The traceback message typically looks something like this
Traceback (most recent call last):
File "..\main.py", line 237, in process_user_input
glfw.poll_events() # Get events from GLFW
File "C:\Python27\lib\site-packages\glfw\__init__.py", line 1340, in poll_events
_glfw.glfwPollEvents()
File "C:\Python27\lib\site-packages\glfw\__init__.py", line 518, in errcheck
_reraise(exc[1], exc[2])
File "C:\Python27\lib\site-packages\glfw\__init__.py", line 51, in _reraise
raise (exception, None, traceback)
TypeError: object.__init__() takes no parameters`
This issue arises since glfw re-raises the exception. Python 3 solves this by using raise exception.with_traceback(traceback). Solutions for this issue are discussed here https://stackoverflow.com/questions/18188563/how-to-re-raise-an-exception-in-nested-try-except-blocks
I tried Laurent LAPORTE's solution using the six-module and it seems to be working properly. However, I'm sure you want to avoid depending on this module.
# glfw/__init__.py
...
# Python 3 compatibility:
try:
_getcwd = os.getcwdu
except AttributeError:
_getcwd = os.getcwd
if sys.version_info.major > 2:
_to_char_p = lambda s: s.encode('utf-8')
def _reraise(exception, traceback):
raise exception.with_traceback(traceback)
else:
import six
_to_char_p = lambda s: s
def _reraise(exception, traceback):
six.reraise(exception, None, traceback)
#raise (exception, None, traceback) # <- Old code
...
Perhaps there is some other way of solving this without using a 3rd part module?
Hi! Thanks for making these bindings! It looks like glfw now releases mac binaries on the official site: https://www.glfw.org/download.html
Would you have any interest in including these in a mac-specific wheel so that users can get started easily?
Installed via pip (pip install glfw
) but when I run
python
>>>import glfw
I get this error:
_default_error_callback = _GLFWerrorfun(_handle_glfw_errors)
MemoryError
Not sure what's going on.
Just also tested deactivating my conda env and installing/running in a simple vanilla python virtualenv and the import worked but I need it through Conda.
Is there a conda incompatibility?
Hello, thank you for creating this awesome library.
it was added/released in glfw hours before the last release of pyGLFW!
I tried glfw.window_hint(0x0002000D, glfw.TRUE)
instead of glfw.window_hint(glfw.MOUSE_PASSTHROUGH, glfw.TRUE)
but found out the compiled library needs updating.
Traceback (most recent call last):
File "./test-clickthrough.py", line 37, in <module>
glfw.window_hint(0x0002000D, 1)
File "glfw/__init__.py", line 1138, in window_hint
_glfw.glfwWindowHint(hint, value)
File "glfw/__init__.py", line 628, in errcheck
_reraise(exc[1], exc[2])
File "glfw/__init__.py", line 52, in _reraise
raise exception.with_traceback(traceback)
File "glfw/__init__.py", line 607, in callback_wrapper
return func(*args, **kwargs)
File "glfw/__init__.py", line 820, in _handle_glfw_errors
raise GLFWError(message)
glfw.GLFWError: (65539) b'Invalid window hint 0x0002000D'
can you please release an update?
On Mac OS 10.13 High Sierra, compiling GLFW does not produce the dylib. In order to create the dylib you need to tell the deployment target version.
export MACOSX_DEPLOYMENT_TARGET=10.8
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.