Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

With multiple sf::RenderWindows, the first one to poll receives the Closed event (Ubuntu / X11) #2649

Closed
MJJBennett opened this issue Aug 15, 2023 · 4 comments

Comments

@MJJBennett
Copy link

MJJBennett commented Aug 15, 2023

Subject of the issue

When managing multiple sf::RenderWindow objects, only one window receives the Closed event (the same window, regardless of which window was closed by the user). Edit: Based on further testing, the window that receives the closed event is almost certainly the one that polls first.

Note: Tested & this is fixed by #2651

Your environment

  • Your OS / distro / window manager used
  • 2.6.x, also confirmed on SFML 3
  • GCC 12
  • No custom flags (can repro with basic example code below)

Steps to reproduce

Tell us how to reproduce this issue. Please provide a minimal, complete and verifiable example, you can use the follow template as a start:

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>

int main()
{
    // Create the main rendering window
    sf::RenderWindow App(sf::VideoMode(800, 600), "App1");
    sf::RenderWindow App2(sf::VideoMode(800, 600), "App2");
    
    // Start game loop
    while (App.isOpen() || App2.isOpen())
    {
        // Process events
        sf::Event Event;
        while (App.pollEvent(Event))
        {
            // Close window : exit
            if (Event.type == sf::Event::Closed) {
                App.close();
                std::cout << "app close" << std::endl;
            }
        }
        while (App2.pollEvent(Event))
        {
            // Close window : exit
            if (Event.type == sf::Event::Closed) {
                App2.close();
                std::cout << "app2 close" << std::endl;
            }
        }

        // Clear the screen (fill it with black color)
        App.clear();
        App2.clear();

        // Display window contents on screen
        App.display();
        App2.display();
    }
}

Expected behavior

Clicking the x button on either window should close that window & only that window.

Actual behavior

Clicking the x button on the second window closes the first window. Clicking the x button on the first window also closes the first window.

Notes

I have a few ideas about what could be happening to cause this behaviour at a high level, but can't test them right now. My guess from the behaviour is that the first window that polls is getting the close event, which would indicate that there isn't distinction at a window level when receiving these particular X messages. This should be easily testable by adding sleeps before the polls to guarantee which poll is checked first after a close.

@ChrisThrasher
Copy link
Member

ChrisThrasher commented Aug 15, 2023

I was able to confirm the correct behavior on macOS and incorrect behavior on Ubuntu. Same behavior with both SFML 2.6.0 and master.

@MJJBennett
Copy link
Author

Can confirm that this is likely due to some kind of shared event queue issue. When running test code using delays before polling for events, whichever event polling loop came after the close button was pressed would get the window closed event. It seems likely that SFML or X11 is not distinguishing between which window receives the event.

I tried to read the relevant SFML code but I'm not familiar with how X11 APIs work, so not sure exactly what's going on. I'm guessing it's an X11 issue, though, because it seems that SFML translates all X11 window events to SF events pretty much the same way, so if this was due to SFML not caring where that X11 event came from,... nothing would work.

Test code:

#include <SFML/Window.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <chrono>
#include <thread>

void sleep_print(std::string p) {
    std::cout << "About to sleep 3s before " << p << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    std::cout << "Slept 3s before " << p << std::endl;
}

int main()
{
    // Create the main rendering window
    sf::RenderWindow App(sf::VideoMode(800, 600), "App1");
    sf::RenderWindow App2(sf::VideoMode(800, 600), "App2");
    
    // Start game loop
    while (App.isOpen() || App2.isOpen())
    {
        // Process events
        sf::Event Event;

        sleep_print("Polling APP for events");
        while (App.pollEvent(Event))
        {
            // Close window : exit
            if (Event.type == sf::Event::Closed) {
                App.close();
                std::cout << "app close" << std::endl;
            }
        }
        sleep_print("Polling APP2 for events");
        while (App2.pollEvent(Event))
        {
            // Close window : exit
            if (Event.type == sf::Event::Closed) {
                App2.close();
                std::cout << "app2 close" << std::endl;
            }
        }

        // Clear the screen (fill it with black color)
        App.clear();
        App2.clear();

        // Display window contents on screen
        App.display();
        App2.display();
    }
}

@MJJBennett MJJBennett changed the title With multiple sf::RenderWindows, the wrong one receives the Closed event (Ubuntu / X11) With multiple sf::RenderWindows, the first one to poll receives the Closed event (Ubuntu / X11) Aug 15, 2023
@kimci86
Copy link
Contributor

kimci86 commented Aug 15, 2023

This is because of this:

Bool checkEvent(::Display*, XEvent* event, XPointer userData)
{
// Just check if the event matches the window
// The input method sometimes sends ClientMessages with a different window ID,
// our event loop has to process them for the IM to work
return (event->xany.window == reinterpret_cast<::Window>(userData)) || (event->type == ClientMessage);
}

It was added as part of #1850.

A ClientMessage event is triggered when closing a window but it is also used by input methods with different window id. Maybe we need to check if the event is about closing the window or not? Any ideas @Edgaru089?

@kimci86
Copy link
Contributor

kimci86 commented Aug 17, 2023

A fix was merged in both 2.6.x and master branches. I think we can close this issue now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants