Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Maximize window: order of events  (Read 6270 times)

0 Members and 1 Guest are viewing this topic.

Oldie

  • Newbie
  • *
  • Posts: 34
    • View Profile
Maximize window: order of events
« on: March 31, 2016, 12:58:02 am »
In the context of a SFML window not covering all the screen, when I maximize it, the mouse pointer typically enters the now maximized window. I get two events reflecting this: sf::Event::Resized and sf::Event::MouseEntered, in this order. In some cases, the order is reversed and I get sf::Event::MouseEntered before sf::Event::Resized. I have not been able to find out why, but moving the window beforehand can apparently change the result; somehow having the window positioned to the left of around 40 pixels (even left of 0) triggers the incorrect order.
My understanding is that sf::Event::Resized should always be fired before sf::Event::MouseEntered.
This has been tested with SFML 2.3.2, and I have not found any commit, issue or PR posterior to that version mentioning this issue on GitHub.

Minimal example:

#include <iostream>

#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow renderWindow(sf::VideoMode(800, 700), "Test event Resized");
        renderWindow.setFramerateLimit(60);
        std::cout << "[init] renderWindow.getPosition(): " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
       
        while (renderWindow.isOpen())
        {
                sf::Event event;
                while (renderWindow.pollEvent(event))
                {
                        std::cout << "event.type = " << event.type << std::endl;
                        switch (event.type)
                        {
                                case sf::Event::Closed :
                                {
                                        renderWindow.close();
                                }
                                break;
                               
                                case sf::Event::Resized :
                                {
                                        std::cout << "[sf::Event::Resized] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                }
                                break;
                               
                                case sf::Event::GainedFocus :
                                {
                                        std::cout << "[sf::Event::GainedFocus] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                }
                                break;
                               
                                case sf::Event::MouseEntered :
                                {
                                        std::cout << "[sf::Event::MouseEntered] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                }
                                break;
                               
                                default :
                                break;
                        }
                }
               
                renderWindow.clear();
                renderWindow.display();
        }
       
        return 0;
}
 
Working on a Tic-tac-toe game

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Maximize window: order of events
« Reply #1 on: March 31, 2016, 08:42:00 am »
And why is it a problem?
Laurent Gomila - SFML developer

Oldie

  • Newbie
  • *
  • Posts: 34
    • View Profile
Re: Maximize window: order of events
« Reply #2 on: March 31, 2016, 12:35:43 pm »
And why is it a problem?

As I said, it looks like it is inconsistent by itself. But I did not stumble on this issue on purpose.
In the game I am working on, during the processEvent phase, I forward every event (except sf::Event::Closed and sf::Event::Resized) to every object that is supposed to be interested. Inside the object, for each type of event, I retrieve useful information from the event. Eg. for sf::Event::MouseEntered:

const auto& mousePosition = renderWindow.mapPixelToCoords(sf::Mouse::getPosition(renderWindow));

This information is immediately copied into the target of a std::function, that is to be executed later on, typically during the update phase. Eg.:

pendingUpdate = [this, mousePosition] ()
{
        updateHovered(mousePosition);
};

In the case of sf::Event::MouseEntered being fired first, the function updateHovered() does not work properly, ie. the object is not hovered despite the mouse being on top of it when that is the case after window resizing.

I did additional tests, to print the value of sf::Mouse::getPosition(renderWindow) for each event:
  • When sf::Event::Resized is fired first, sf::Mouse::getPosition(renderWindow) gives the new value immediately, which is correct.
  • When sf::Event::MouseEntered is fired first, sf::Mouse::getPosition(renderWindow) gives the new value immediately as well (before sf::Event::Resized being polled). This looks fine because another value would make no sense. But at this point, this value is mapPixelToCoords’ed, which stores coordinates relative to the old window size, ie. x and y are unchanged after mapPixelToCoords(), like they would be with the old window state (view not stretched). So there is a mix of the old and the new happening here, which is not a good thing.

I hope I am clear enough; I can provide a full use case with figures if there is a need for a better explanation.

Btw I forgot to mention my environment in the OP: Debian GNU/Linux 8 amd64.

Updated code to check the explained behaviour:

#include <iostream>

#include <SFML/Graphics.hpp>

int main()
{
        sf::RenderWindow renderWindow(sf::VideoMode(800, 700), "Test event Resized");
        renderWindow.setFramerateLimit(60);
        std::cout << "[init] renderWindow.getPosition(): " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
       
        while (renderWindow.isOpen())
        {
                sf::Event event;
                while (renderWindow.pollEvent(event))
                {
                        std::cout << "event.type = " << event.type << std::endl;
                        std::cout << "sf::Mouse::getPosition(renderWindow) = " << sf::Mouse::getPosition(renderWindow).x << ", " << sf::Mouse::getPosition(renderWindow).y << std::endl;
                        switch (event.type)
                        {
                                case sf::Event::Closed :
                                {
                                        renderWindow.close();
                                }
                                break;
                               
                                case sf::Event::Resized :
                                {
                                        std::cout << "[sf::Event::Resized] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                }
                                break;
                               
                                case sf::Event::GainedFocus :
                                {
                                        std::cout << "[sf::Event::GainedFocus] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                }
                                break;
                               
                                case sf::Event::MouseEntered :
                                {
                                        std::cout << "[sf::Event::MouseEntered] renderWindow.getPosition() = " << renderWindow.getPosition().x << ", " << renderWindow.getPosition().y << std::endl;
                                        std::cout << "[sf::Event::MouseEntered] renderWindow.mapPixelToCoords(sf::Mouse::getPosition(renderWindow)) = " << renderWindow.mapPixelToCoords(sf::Mouse::getPosition(renderWindow)).x << ", " << renderWindow.mapPixelToCoords(sf::Mouse::getPosition(renderWindow)).y << std::endl;
                                }
                                break;
                               
                                default :
                                break;
                        }
                }
               
                renderWindow.clear();
                renderWindow.display();
        }
       
        return 0;
}
Working on a Tic-tac-toe game

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
Re: Maximize window: order of events
« Reply #3 on: March 31, 2016, 03:51:44 pm »
If I remember correctly, SFML just provides events in the order as they are provided by the OS.

So this size/position mismatch goes for how long? One frame? Half a frame?
I think every user can deal with possibility of some 16ms artifact when changing the window size.

Why do you call sf::Mouse::getPosition() when dealing with a mouse event? The mouse event already provides the mouse coordinates.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Oldie

  • Newbie
  • *
  • Posts: 34
    • View Profile
Re: Maximize window: order of events
« Reply #4 on: March 31, 2016, 04:27:38 pm »
If I remember correctly, SFML just provides events in the order as they are provided by the OS.
I hope it does in principle. ;) Would this mean that the OS sends these events in reverse order in some cases?
What about other platforms than Linux, can anyone using Windows or OSX test this issue?

Quote
So this size/position mismatch goes for how long? One frame? Half a frame?
I think every user can deal with possibility of some 16ms artifact when changing the window size.
In the use case described above, where the object is not set to hovered state despite being covered by the mouse, the problem lasts… as long as you don’t move the mouse essentially. Otherwise it gets back to normal of course. We could always argue that the user can just move the mouse in his momentum of resizing the window and be done with it, but I feel like the underlying process is not correct.

Quote
Why do you call sf::Mouse::getPosition() when dealing with a mouse event? The mouse event already provides the mouse coordinates.
Of course, I just use it it for the purpose of my test, and otherwise for event types that have no data.
Working on a Tic-tac-toe game

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
Re: Maximize window: order of events
« Reply #5 on: March 31, 2016, 05:48:19 pm »
Would this mean that the OS sends these events in reverse order in some cases?
You'd have to check with the various window manager and OS documentations, but I think in generally it's not a very good idea to rely on the order of events.

In the use case described above, where the object is not set to hovered state despite being covered by the mouse, the problem lasts… as long as you don’t move the mouse essentially.
You can see that case in many other applications, most likely unrelated to the order of events. I personally am not surprised when I change the window size and then don't move my mouse, that some hover effect is not being executed and I doubt that this is just my feeling.
I mean if you think about it, does it break anything? Can you first try and implement anything else or is this the last thing you need to get working?

In the end there's no much SFML can do about this. Delaying events to check for other events is just not an option. Since you're on Linux, what WM do you use? Maybe it's a WM bug?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Oldie

  • Newbie
  • *
  • Posts: 34
    • View Profile
Re: Maximize window: order of events
« Reply #6 on: March 31, 2016, 06:27:23 pm »
You can see that case in many other applications, most likely unrelated to the order of events. I personally am not surprised when I change the window size and then don't move my mouse, that some hover effect is not being executed and I doubt that this is just my feeling.
I mean if you think about it, does it break anything? Can you first try and implement anything else or is this the last thing you need to get working?

In the end there's no much SFML can do about this. Delaying events to check for other events is just not an option. Since you're on Linux, what WM do you use? Maybe it's a WM bug?
The application will work fine because it’s a corner case. I guess I could call that function updateHovered() when sf::Event::Resized is fired as well, but I feel it would just be a hack not worth the hassle.

I use MATE, so the WM is called Marco (fork from GNOME’s Metacity). Maybe asking them about it could solve the issue, I will think about it.

Anyway, thank you for clearing that up.
Working on a Tic-tac-toe game

 

anything