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

Author Topic: Slightly broken position and setPosition implementations in Mac sf::Window  (Read 2501 times)

0 Members and 1 Guest are viewing this topic.

TheMaskedFox

  • Newbie
  • *
  • Posts: 7
    • View Profile
I'm not sure if this is due to changes between one version of OS X and another, or if this is just broken across all versions.  I'm on Lion.

If I call position, and then use its returned point as input to setWindowPositionToX:Y:, the window moves.  That shouldn't happen. :)

Take a look at the following rewrites, which solve the problem for me.  I hope, but don't have an easy way to test, that this rewrite corrects the behavior across all of SFML's supported versions of OS X.

Quote
////////////////////////////////////////////////////////////
-(NSPoint)position
{
    NSRect frame = m_window.frame;
    NSPoint pos = frame.origin;
   
    // Flip for SFML window coordinate system.
    pos.y += frame.size.height;
    pos.y = m_window.screen.frame.size.height - pos.y;

    return pos;
}


////////////////////////////////////////////////////////.
-(void)setWindowPositionToX:(unsigned int)x Y:(unsigned int)y
{
    NSPoint point = NSMakePoint((int)x, (int)y);
    NSScreen *screen = m_window.screen;

    // Flip for SFML window coordinate system.
    point.y = m_window.screen.frame.size.height - point.y;

    // Place the window.
    [m_window setFrameTopLeftPoint:point];
   
    if (screen != [m_window screen]) {
        // Oops.  Coordinates were for a different screen.  Do-over.
        [self setWindowPositionToX:x Y:y];
    }
}

The key differences:

position should be using the window's frame, not the OpenGL view's frame (unless there's some reasoning for using the OpenGL view that I'm missing.)

position also must account for the window's size when flipping the y coordinate.

setWindowPositionToX:Y: should be taking ints, not unsigned ints.  It is legitimate for a window to have a negative X or Y, especially in the case of multiple displays (which my changes appear to support without issue).

setWindowPositionToX:Y: also needs to recognize that the coordinates may not be for the main display, and must use the proper display height for adjustment.  There's probably a better way to handle that case than what I did, but what I did is working.  My lazy implementation just checks to see if the repositioned window ended up on a different screen, and if so, recognizes the mistake and repeats the positioning now that m_window.screen points to the screen that the coordinates were supposed to reference.

This came up when I was trying to go from Windowed to Fullscreen to Windowed.  My window would not end up in the right place after exiting Fullscreen.  These changes resolve that.

EDIT:
Upon further reflection, this works fine for side-by-side displays, but is still slightly deficient in a case of vertically or diagonally positioned displays.  I'm doing at bit more exploration to see if I can gracefully resolve vertical positioning despite dealing with a coordinate system translation in the process.

EDIT 2:
I stand corrected.  (Mostly...)  :)

Turns out this works pretty well for vertically oriented displays too.  It's not perfect.  If the window is placed such that it sits partially in one window's bottom right corner, and partially in another window's top left corner, the positioning will be slightly off if you use the values from a getPosition in a call to setPosition.  However, this solution at least changes the problem from "happens all the time" to "happens in one edge case", and in that edge case the incorrect behavior is now much more minimal.

I think it's as close as I can get without SFML itself being more multi-display aware.  I'm going to push this to my fork of SFML and open a pull request.  If SFML's maintainers don't approve, that's cool.

This whole issue specifically comes up when switching between Window and Fullscreen.  Since SFML dictates that the window has to be recreated each time, there's no internal state on the window itself by which a previous size and location can be remembered.  The application itself is left with the responsibility of implementing a fullscreen switch and ensuring predictable behavior.  This change at least makes getPosition and setPosition behave in a more predictable manner.
« Last Edit: October 05, 2012, 05:49:57 pm by TheMaskedFox »

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
I'll look into it but could you give me a minimal code that reproduce the problem ? Thanks.
SFML / OS X developer

TheMaskedFox

  • Newbie
  • *
  • Posts: 7
    • View Profile
I'm running this on OS X 10.7.4.  Two displays, secondary positioned to the left of main.  The window opens on the main display.  When I hit spacebar, the window jumps and ends up positioned across both displays, starting in the lower left of the secondary and carrying over to the main.  The window is mostly off the bottom of the displays.

Anytime I call getPosition and apply the output back into setPosition, the window should remain exactly where it is currently positioned.

Quote
int main(int argc, char* argv[])
{
    sf::Event event;
    sf::Window window(sf::VideoMode(320, 240), "Position Test");
    sf::Vector2i pos;

    while (window.isOpen()) {
        while (window.pollEvent(event)) {
            switch (event.type) {
                case sf::Event::Closed:
                    window.close();
                    break;
               
                case sf::Event::KeyPressed:
                    if (sf::Keyboard::Space == event.key.code) {
                        pos = window.getPosition();
                        window.setPosition(pos);
                    }
                    break;
                   
                default:
                    break;
            }
        }
    }
   
    return 0;
}

I managed to mostly resolve this in my fork of SFML.  Take a look at https://github.com/SFML/SFML/pull/295 to see my solution.

Hiura

  • SFML Team
  • Hero Member
  • *****
  • Posts: 4321
    • View Profile
    • Email
Indeed there is an issue here!
SFML / OS X developer