FlorianRhiem / pyGLFW

Python bindings for GLFW
MIT License
233 stars 36 forks source link

Cannot create Window on Wayland #42

Closed almarklein closed 4 years ago

almarklein commented 4 years ago

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: https://github.com/glfw/glfw/issues/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?

FlorianRhiem commented 4 years ago

Hey, thank you for reporting this. I wasn't aware that there were GLFW errors that were just meant as warnings or hints and I'm not sure how to detect this. The error code is the generic code for platform errors, so that cannot be used to filter out these errors. Until there's some way to know that an error is not meant as an error but rather as a warning, setting glfw.ERROR_REPORTING = False should be the workaround. Error reporting seems too useful to me to disable it by default.

I don't have an Ubuntu system at the moment, could you test whether this error is also raised if the window should not be focused, i.e. if the GLFW_FOCUSED window hint (or glfw.FOCUSED in Python) is set to False by calling glfw.window_hint(glfw.FOCUSED, False) before creating the window?

If this works I could somewhat understand that the focusing failure is considered an error, although it might make more sense to document platform specific issues and ignore window hints on the platforms that cannot possibly fulfill them.

almarklein commented 4 years ago

Could you test whether this error is also raised if the window should not be focused, i.e. if the GLFW_FOCUSED window hint (or glfw.FOCUSED in Python) is set to False

In that case it works without errors. Note that calling glfw.show_window(w) will still produce that error, which supposedly can be avoided by also setting the FOCUS_ON_SHOW window hint, except that (my version of) glfw does not accept that hint.

Here's an example code that adds the fix on Wayland. Do you think we should add this workaround in e.g. glfw.create_window() or glfw.init()?

import os
import sys

import glfw

glfw.init()

if sys.platform.startswith("linux"):
    if "wayland" in os.getenv("XDG_SESSION_TYPE", "").lower():
        glfw.window_hint(glfw.FOCUSED, False)  # prevent Wayland focusing error
        # glfw.window_hint(glfw.FOCUS_ON_SHOW, False)  # Invalid window hint 131084

w = glfw.create_window(640, 480, "glfw window", None, None)
FlorianRhiem commented 4 years ago

I don't want to alter the behavior of GLFW in the wrapper, but I think that might be something you could suggest as a change to GLFW itself, especially if GLFW_FOCUSED is impossible to implement on Wayland.

almarklein commented 4 years ago

It looks like the error messages should not be considered "fatal", see this comment. Perhaps instead of raising when we detect an error message, we should check the output of an operation to see whether it succeeded, and raise an error when it did not. I can see how this would be a big change though, and possibly break current behavior.

FlorianRhiem commented 4 years ago

I think it would be best to switch to Python warnings then. If the wrapper sets the warnings filter to 'error' for GLFWErrors and does not send a warning if ERROR_REPORTING is False, then this would not be a breaking change. The user can then set the warnings filter to default and get a print instead of an exception.

The wording in the comment you linked would suggest that simply printing the warning (i.e. not setting the warnings filter) would be more fitting, though I'm reluctant to do that in a minor release, as it might break user code.

FlorianRhiem commented 4 years ago

I've implemented a draft of this in e107b1baabd0822475c97654ac500ae9f76bc4f9.

almarklein commented 4 years ago

Idea: what about (ab)using the ERROR_REPORTING flag to set the behavior:

And False and True can map to 'ignore' and 'error' for backwards compatibility.

FlorianRhiem commented 4 years ago

Yes, that keeps backwards compatibility and gives users plenty of options. I've added more ERROR_REPORTING options in 8904cbf64e5fe656c898525fc2442a7385609dab:

FlorianRhiem commented 4 years ago

I've merged the branch into master and released it as v1.10.0. Thank you, Almar!

almarklein commented 4 years ago

Thank you Florian, for being so proactive in resolving this issue!

einarf commented 4 years ago

@FlorianRhiem deserves a medal or something. It's the truth.

NaNraptor commented 2 years ago

So this seems to be a "resolved issue" although as a dumbass user of this library how would i go about seeing something that is not: image

here is the minimal code i am running:

import glfw

glfw.init()

glfw.ERROR_REPORTING = False

window = glfw.create_window(640, 400, "Window", None, None)
glfw.make_context_current(window)

while not glfw.window_should_close(window):
    glfw.swap_buffers(window)
    glfw.poll_events()

glfw.terminate()

glfw.ERROR_REPORTING = False hides the errors but that doesn't resolve them glfw.window_hint(glfw.FOCUSED, False) gets rid of that initial error message but I still see this "broken" window

I additionally get this error, when I hover over the broken window:

...site-packages/glfw/__init__.py:906: GLFWError: (65544) b'Wayland: Standard cursor not found'
  warnings.warn(message, GLFWError)

Specs: I am running Ubuntu 21.10 using Wayland with the 16.14 kernel Code is running in a venv with the following packages installed:

Package       Version
------------- -------
glfw          2.5.1
pip           20.3.4
pkg-resources 0.0.0
PyOpenGL      3.1.6
setuptools    44.1.1

I also never did apt install for any glfw packages so I assume it comes with the wheel or whatever (educate me if you have the time :))

FlorianRhiem commented 2 years ago

Hey @NaNraptor, it looks like you're swapping the buffer, but never drawing anything in it or clearing it, so that you're seeing some (semi-random) framebuffer content. Please try the following:

import glfw
from OpenGL.GL import *

glfw.init()

glfw.ERROR_REPORTING = False

window = glfw.create_window(640, 400, "Window", None, None)
glfw.make_context_current(window)
glClearColor(1, 0, 0, 1)
while not glfw.window_should_close(window):
    glClear(GL_COLOR_BUFFER_BIT)
    glfw.swap_buffers(window)
    glfw.poll_events()

glfw.terminate()

and let me know what happens. That should clear the buffer with solid red.

NaNraptor commented 2 years ago

Hi Florian,

Thanks for the super fast response! Yes that does fix the window contents, but what about the minimize, maximize and close buttons? Am I not seeing them because Im doing something wrong or because wayland is terrible and sucks?

EDIT: and if it is wayland, how would I go about adding decorations?

NaNraptor commented 2 years ago

Also I am still getting the following error:

...site-packages/glfw/__init__.py:906: GLFWError: (65544) b'Wayland: Standard cursor not found'
  warnings.warn(message, GLFWError)
FlorianRhiem commented 2 years ago

Ah, sorry, I thought you meant the framebuffer content.

I don't have much experience with Wayland, but please try setting the DECORATED window hint before creating the window, by calling glfw.window_hint(glfw.DECORATED, glfw.TRUE) before calling glfw.create_window. Hopefully that'll work.

FlorianRhiem commented 2 years ago

Also I am still getting the following error:

...site-packages/glfw/__init__.py:906: GLFWError: (65544) b'Wayland: Standard cursor not found'
  warnings.warn(message, GLFWError)

The GLFW documentation mentions that some standard cursors are not supported by all Wayland cursor themes, so that could be the cause of this warning.

NaNraptor commented 2 years ago

Sadly that still leaves me with a white border with no buttons, also resizing is broken - resizing always increases the width of the window no matter which way I drag

Do you have any idea where I might go for further information on this if you personally dont know?

NaNraptor commented 2 years ago

The GLFW documentation mentions that some standard cursors are not supported by all Wayland cursor themes, so that could be the cause of this warning.

What can I do about that? The documentation mentions nothing of a resolution

FlorianRhiem commented 2 years ago

Hm, you might be seeing this issue: https://github.com/glfw/glfw/issues/1257 though it should be resolved in GLFW and current versions of Gnome and KDE, if I understand the comments correctly.

I don't think there is any resolution, basically this means that on Wayland, those cursors might be missing, depending on the cursor theme. Luckily, they're not the most common, so you can probably just ignore the warning, and keep it in mind for when you start using those cursors.

NaNraptor commented 2 years ago

Hm, you might be seeing this issue: glfw/glfw#1257 though it should be resolved in GLFW and current versions of Gnome and KDE, if I understand the comments correctly.

From the linked issue I see:

We can now close this issue as all relevant compositors now support one of these two protocols, if any user still doesn’t see decorations we can just tell them to update their compositor. slightly_smiling_face

But no explanation as to what updating a compositor even is :D. Do you think I should open an issue over at glfw?

FlorianRhiem commented 2 years ago

The compositor is basically just a piece of software involved in rendering windows. You mentioned that you're using Ubuntu 21.10, so you're currently using the version that is being provided by their software sources. It shouldn't be all that old, and the issue links a fix that's already 3 years past, so I don't know what exactly is going wrong there.

I would recommend that you try to build and run the example from here: https://www.glfw.org/documentation.html It is basically the same code, but in C, that way we'll know this Python wrapper isn't mucking things up.

Then try compiling the current develop branch of GLFW and see if the issue persists with that version, or if it might have been fixed in the meantime. If it persists, hopefully someone at the GLFW Discourse will be able to help or you might open an issue in the GLFW repo.

NaNraptor commented 2 years ago

I would recommend that you try to build and run the example from here: https://www.glfw.org/documentation.html It is basically the same code, but in C, that way we'll know this Python wrapper isn't mucking things up.

After some time setting up the latest glfw from my apt store and figuring out how the linker for gcc works on the command line i was able to compile and run the code in that link (minus the glClear function call). I am met with the exact same window as when I run it through the python lib, that is the one with no buttons.

I will now attempt to compile latest glfw and report back

NaNraptor commented 2 years ago

Okay! I fixed it. So after compiling the latest glfw (3.4) with the flags -D GLFW_USE_WAYLAND=1 and -D BUILD_SHARED_LIBS=ON and linking it correctly (linking is a pain and I hate it) it finally works: image

@FlorianRhiem do you think it would be somehow possible to include the .so files for glfw that are compiled with the -D GLFW_USE_WAYLAND=1 flag? By include I mean "with the wheel" whatever that means (or with the pedal why not lol :D)

Although honestly im not sure what Im talking about here as this newly compiled lib might need different python binding? Or something? I really dont know, just asking to see if this lib can make it possible for python users under wayland to not have to worry about compiling glfw

FlorianRhiem commented 2 years ago

Good to hear! The libraries I'm including in the wheel for Linux are being built with -D GLFW_USE_WAYLAND=1, so the difference must be with using the develop branch and some commit from there that fixes this issue. The wheels include GLFW 3.3.6, the latest released version, as 3.4 isn't released yet.

NaNraptor commented 2 years ago

Ah I see! So if I substitute my newly compiled .so file with the one provided by you would everything magically work itself out?

EDIT: The other way around - substitute your file with mine

EDIT2: it did work I now a see good window :). Although Im uncertain if some bindings might be broken because of this substitution?

FlorianRhiem commented 2 years ago

The develop branch may contain some issues, but given that it also fixes the one that's been troubling you, it's definitely the way to go. This should work fine.