SFML community forums

General => SFML development => Topic started by: Foaly on February 01, 2018, 11:35:24 pm

Title: Window state
Post by: Foaly on February 01, 2018, 11:35:24 pm
Hello everybody,
I was looking into a ticket that I have already been working on in the past. It is on maximing a window from code (https://github.com/SFML/SFML/issues/744). Reading over the discussion again it seems to end with an already pretty good concept for an API. I though about it some more and I want to propose a design here. I'd like to hear your thoughts and if we can agree on it or develop it further I would like to start an implementation soon. Oh and a thing you guys are gonna like: we don't have to change the existing API, except for one deprecation ;)

So I would suggest this:
enum State
{
    Windowed,
    Minimized,
    Maximized,
    Fullscreen
};


sf::Window::State state = sf::Window::State::Minimized;
window.create(videoMode, title, style, settings, state);
state = window.getState();
window.setState(state);

So as you can see we have a seperation between state and style. Style is now only for the appearance/decoration of a window. The state of the window can now be described seperatly. An enum somewhere contains the possible window states. States are exclusive, so a window can only ever have one state. The create method will be extended by another parameter for the style, which can default to Windowed. The platform implementation of create will then open the window in the given state. There is also a getter and a setter in sf::Window. The setter will simply apply the state to the window. The getter will return the windows current state. Those are all the additions to the API. The Fullscreen window style would have to be deprecated in order to make a clear distinction between style and state.

This API would have two welcome side effects. You could finally switch to fullscreen mode and back (at least I have found it very annoying in the past that you always have to recreate the window for that, especially since things like the mouse visibility are not saved). Also it would allow creating a hidden/invisible window on creation by passing the minimized state to the create function.

So I would like to hear your thoughts on this :)

Title: Re: Window state
Post by: FRex on February 02, 2018, 12:45:35 am
Looks fine to me, maybe allowing creating hidden Windows would be an additional nice thing to have?

It looks close to how LCL does it too: http://lazarus-ccr.sourceforge.net/docs/lcl/forms/twindowstate.html

I'd do it differently (but I'm biased towards Windows): add a new style flag to allow creating a hidden window and add a maximize() call but it might come from the fact that latter is doable with WinApi right now and former isn't (not easily anyway, I could create my entire own window handle and use the other constructor...) so there is a flicker on Window creation due to initial non-maximized Window being shown.
Title: Re: Window state
Post by: Foaly on February 02, 2018, 01:21:49 am
Cool, thank!
Well I think with the proposed API you could achive similar results. When you pass the style to the create method the style is applied to the window directly on creation. On windows this is possible by passing the dwStyle flag to CreateWindow (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632679(v=vs.85).aspx). The style can be any of these (https://msdn.microsoft.com/en-us/library/windows/desktop/ms632600(v=vs.85).aspx). So in order to get a hidden window you could create a minimized window. Of course you could also start with a maximized right away.
On MacOS NSWindow (https://developer.apple.com/documentation/appkit/nswindow) does not seem to have a way to apply a style on init. We will have to see if there is a flickering when applyed immediately afterwards.
Title: Re: Window state
Post by: FRex on February 02, 2018, 01:33:02 am
A minimized window still appears in the task bar. A true hidden Window would just not have WS_VISIBLE set in dwStyle on creation on Windows.

The only possible use for this is if someone wants a hidden window without flicker (I have no idea what for, I wanted it to not have flicker before I maximize it with WinApi).

I know how to look up stuff in WinApi or SFML source code but creating own window is still a lot of additional code to go around this compared to a single ShowWindow to maximize a window via handle.

I'm just saying since even if I don't now need hidden windows if this is accepted someone else might and SFML has hidden windows already, just not initially hidden ones and that causes a flicker on Windows as if a virus has just popped up a cmd.exe window to hack you or something tried to start and failed or something... it's also visually jarring.
Title: Re: Window state
Post by: Sub on February 02, 2018, 01:56:00 am
Out of pure curiosity, what's the use case in having a hidden window?

edit:  Also, thank you Foaly.  This is something I've long wanted in SFML.
Title: Re: Window state
Post by: FRex on February 02, 2018, 02:19:53 am
I don't know, maybe something like not destroying the Window and GL context it has if you just want it to not be shown for some time.

I wanted the initial hidden window to then maximize it myself and have no flicker due to initial one being shown.

SFML already has a setVisible function too so there has to be some use deemed important enough.
Title: Re: Window state
Post by: Laurent on February 02, 2018, 08:34:35 am
The proposed API is fine and can be done in SFML 2.x, but I have one problem with it so let me suggest a slight variation.

The thing is, it adds yet another argument to the constructor and create function ; moreover, if we don't want to break API compatibility, it has to be the last one but the "right" order for it would clearly be between "style" and "settings". Not the end of the world, but not ideal.

Why do we have so many arguments to create the window? Because it's shown directly as it is created, so it has to have all its final attributes right away.

What if instead we allow to create an invisible window, then set whatever attributes with (already existing or new) setter functions, and finally show it? Yes, this is basically what FRex suggests.

All we'd need is an additional style flag, something like sf::Style::Hidden -- which is fine because the style is set at creation time and can never be changed later -- and then call setState, setTitle or whatever, and finally setVisible(true).

TL;DR: keep everything as proposed, but simply replace the additional "state" argument with a new "Hidden" style flag.
Title: Re: Window state
Post by: eXpl0it3r on February 02, 2018, 10:29:15 am
By "replace" do you mean, use it as default value?
Title: Re: Window state
Post by: Laurent on February 02, 2018, 11:02:22 am
I mean, don't add the "state" argument to constructor, instead provide a new "Hidden" style. As for the defaults, there's no need to change the current behaviour.
Title: Re: Window state
Post by: Foaly on February 02, 2018, 11:24:13 am
Thanks for the feedback.
But now you got me confused. I understood it like exploiter explained it.
So to my understanding you propose the following: As discribed above by me, but don't add a new style parameter to create, but instead always create a window in the hidden state. So a reagular call would look something like this:
window.create(videoMode, title, style, settings);
// or
window.create(videoMode, title);
// window is NOT visible at this point

// call some setters

window.setState(sf::State::Windowed); // or maximized or whatever
Title: Re: Window state
Post by: Laurent on February 02, 2018, 12:51:53 pm
Is that really what I said? :o

You got me wrong, here is what I suggest:

// NO CHANGE, create visible and windowed, as in current version
window.create(videoMode, title, style, settings);

// ADDED function
window.setState(sf::State::Maximized);

// BUT IF YOU WANT you can also create the window hidden, configure it and show it later
window.create(videoMode, title, style | sf::Style::Hidden, settings);
window.setState(sf::State::Fullscreen);
window.setVisible(true);

So it's:
- add the sf::State enum and Window::setState/getState functions, as proposed initially
- deprecate sf::Style::Fullscreen, of course
- add sf::Style::Hidden (it's the only thing that changes in my proposal)
Title: Re: Window state
Post by: Foaly on February 02, 2018, 04:14:46 pm
I thought it sounded weird, thats why I was confused :D
Well ok, I guess this would be possible too. I don't really see anything that speaks against it. It is nice to have the constructor with few arguments, but I wouldn't consider the wrong order a real problem. One thing that will be unexpected for users is that the default way to create a fullscreen window will look like this:
window.create(videoMode, title, style | sf::Style::Hidden, settings);
window.setState(sf::State::Fullscreen);
window.setVisible(true);
Which might be confusing as you didn't really have to deal with those things before.
Also thinking about it I would consider the visibility more of a state than a style, but then the design you proposed wouldn't work.
Another question I have is what happens if the user only passes sf::Style::Hidden to a window and then calls setVisible(true)? Should a default window (Titlebar | Resize | Close) or a window without any decorations (None) be shown?
Title: Re: Window state
Post by: Laurent on February 02, 2018, 05:23:26 pm
Quote
I wouldn't consider the wrong order a real problem
I do ;D

Quote
One thing that will be unexpected for users is that the default way to create a fullscreen window will look like this
Only for those who care about seeing the window not fullscreen for a fraction of second. For the rest of the world, it's just
window.create(videoMode, title, style, settings);
window.setState(sf::State::Fullscreen);
... which looks more natural.

Quote
Also thinking about it I would consider the visibility more of a state than a style, but then the design you proposed wouldn't work.
Well, visibility is a state (we have set/getVisible that we can call anytime), maybe naming the flag sf::Style::InitiallyHidden would be less confusing? Because that's what this flag is for: deciding the initial visibility of the window.

Quote
Another question I have is what happens if the user only passes sf::Style::Hidden to a window and then calls setVisible(true)? Should a default window (Titlebar | Resize | Close) or a window without any decorations (None) be shown?
The addition of sf::Style::Hidden doesn't change anything, if you don't pass other flags it's equivalent to sf::Style::None.
Title: Re: Window state
Post by: Hapax on February 03, 2018, 04:52:30 pm
I quite like the proposal of adding sf::Style::Hidden to allow the window to be hidden initially and allow some state alterations before making the window visible.

However, instead of deprecating sf::Style::Fullscreen, it could remain so that it would automatically set the state. This would continue to allow the previous (and still simple) and expected SFML 2 code:
window.create(videomode, title, sf::Style::Fullscreen, settings);

This would then automatically set the state to sf::State::Fullscreen. If sf::Style::Fullscreen remains as exclusive to other styles then a decision would need to be made as to which style the window actually is for when the state is set to windowed. However, the option now is to allow the style to be provided along with the fullscreen 'style' for this reason. Of course, if only sf::Style::Fullscreen is used here, this would mean sf::Style::None | sf::Style::Fullscreen.
Title: Re: Window state
Post by: Laurent on February 04, 2018, 11:20:03 am
Quote
However, instead of deprecating sf::Style::Fullscreen, it could remain so that it would automatically set the state.
Sounds like really confusing to have both sf::Style::Fullscreen and sf::State::Fullscreen. And why would we make a special case for this one, and not for the others? I think we should make things simple, clean and consistent.
Title: Re: Window state
Post by: Hapax on February 05, 2018, 12:34:38 am
why would we make a special case for this one, and not for the others?
Because it already exists this way and would allow fully backwards compatibility with previous SFML 2 versions.

I think we should make things simple, clean and consistent.
Forcing a change from the simple fullscreen style to using multiple lines for a fullscreen window makes it become less simple.
Clean and consistent comes with either redesigning the interface (version 3) to allow the new stuff or not implementing the new stuff at all. Otherwise it costs simplicity as mentioned.
Title: Re: Window state
Post by: Laurent on February 05, 2018, 06:40:21 am
Quote
Because it already exists this way and would allow fully backwards compatibility with previous SFML 2 versions.
I personally prefer to deprecate things if it allows us to keep the API clean. "X is done this way because of historical reasons" is always a bad argument when you explain something to your users.

Quote
Forcing a change from the simple fullscreen style to using multiple lines for a fullscreen window makes it become less simple.
This change just moves Fullscreen from being a fixed style to a changeable state. It's not "less simple", it's just different and more powerful.

Quote
Clean and consistent comes with either redesigning the interface (version 3) to allow the new stuff or not implementing the new stuff at all.
So you're completely against deprecation? Think about all these users complaining about SFML being stuck in endless discussions, this is not really what they want to hear ;D
Title: Re: Window state
Post by: Hapax on February 05, 2018, 05:27:11 pm
Quote
Clean and consistent comes with either redesigning the interface (version 3) to allow the new stuff or not implementing the new stuff at all.
So you're completely against deprecation? Think about all these users complaining about SFML being stuck in endless discussions, this is not really what they want to hear ;D
No, no, not at all. This this question of whether or not to stick to not breaking the interface or allowing it to break. Since SFML's stance seems to be firmly on not breaking, it would be better to not change something so drastic, requiring multiple lines to set up a full screen window, for example. If it did allow breaking (including breaking deprecation), the order of parameters could easily be changed to suit, for example.

Note that SFML's deprecation method means that it is still technically allowed so the implementation of fullscreen style would still have to be implemented anyway. This means that both methods need to be provided, which can be much less clean.


I'm not personally adverse to serious breaking changes, to be clear. I'm all for improvement and evolution and am always willing to update code to follow the most recent version. It's one of those points though, where if you allow this thing, do you allow some other thing, which situation is so often remarked upon.
Title: Re: Window state
Post by: Laurent on February 05, 2018, 08:32:32 pm
So what do you propose, actually? Is it just about not deprecating sf::Style::Fullscreen?
Title: Re: Window state
Post by: Foaly on February 07, 2018, 07:44:58 pm
I though we finally desided in that recent discussion, that we want to start moving forward with SFML again. And while keeping the API freeze in place use deprecation to implement new features. This would be such a case :)
I know it feels a little clunky to have 2 calls now to open a window in fullscreen instead of one. Thats why I originally proposed to have state as a parameter in the window constructor. Laurent argued against it, since the same can be accived with a initially hidden window that is then put into fullscreen state. The new API is also more powerful in the ragard, that you can make all the changes to a window, before showing it.


Sooo I uploaded a first implementation for MacOS. Not everything works, but it gives you an idea and can serve as a foundation for further discussions. You can find it in my feature/window_state (https://github.com/Foaly/SFML/tree/feature/window_state) branch.

So here are some implementation questions for MacOS. I haven't programmed a lot of Objective C (none actually :D ) so some questions might be easy to answer.

* when do I use self and when nil as parameters on NSWindow functions (both seem to work)?
* For the Hidden Style, calling orderOut directly after window creation doesn't hide the window. Actually on OSX right now it doesn't work if you do this:
sf::RenderWindow window(sf::VideoMode(800, 600), "Example");
window.setVisible(false);
From my test setVisible only starts working after the second run trough pollEvents.
I did look into what other librarys or people on the web did (there isn't much), but they all seem to be using orderOut.

* The fullscreen state is not implemented yet, as I'm not quiet sure of how to go best about it. It would probably need some refactoring of the init methods. I would need some input from mantognini on this.
* Also I get warning for the WindowImplDelegateProtocol methods not being implemented for SFViewController. From what I see the implementaion has to be dupicated, right? I am not sure what the design is here.


So yeah I mostly need mantognini input on the Mac version :)
I will try to start a windows implementation tonight.


edit: fixed one bug! also list and [ s ] together seems to be broken
Title: Re: Window state
Post by: Hapax on February 07, 2018, 09:03:49 pm
So what do you propose, actually? Is it just about not deprecating sf::Style::Fullscreen?
Adding the state to the constructor as originally suggested.

This is simpler overall; opening a fullscreen window with SFML is incredible simple at the moment. The (as Foaly put it) "clunky" code to create one with multiple lines may put off some more casual users or new users, which I imagine is not the intent.
Title: Re: Window state
Post by: Mario on February 08, 2018, 09:19:15 am
Rather than hiding all windows initially (it's what I understood?), why not adding a `sf::Style::Hidden`, that basically works like a call `window.setVisible(false)`?
Title: Re: Window state
Post by: Laurent on February 08, 2018, 09:49:46 am
Quote
Rather than hiding all windows initially
Nobody suggested that, as it would be a silent change in existing behaviour.

Quote
why not adding a `sf::Style::Hidden`, that basically works like a call `window.setVisible(false)`?
This is precisely what I suggest.
Title: Re: Window state
Post by: Foaly on February 11, 2018, 05:10:19 pm
Hello there!
I just pushed my windows implementation for the window state API. You can find it here (https://github.com/Foaly/SFML/commit/22fd13733499963d3e184fffbb004d26ba624de8).
From my tests it works quiet nice, but more testing and feedback would be great.
I have also encountered a really weird bug, which prohibits you from switching to fullscreen a second time, after you've switched back to windowed mode. The comparison on this line (https://github.com/Foaly/SFML/commit/22fd13733499963d3e184fffbb004d26ba624de8#diff-44d9a7191ef326135520369f7db5e2f4R379) always fails, even if my debugger tells me state is State::Windowed. It is super weird and I can't figure it out, maybe somebody else knows more.

Here is he test code I have been using. Feel free to test and comment!
(click to show/hide)

Also maybe some more people have an opinion on whether or not to have a state parameter in the constructor :)
Title: Re: Window state
Post by: Foaly on February 15, 2018, 05:47:43 pm
No comments :( ? Nobody tested?
Title: Re: Window state
Post by: Sub on February 16, 2018, 08:36:48 pm
There's a fairly strong chance that I'm an idiot, but I can't compile it.

Code: [Select]
/home/dan/Desktop/SFML-22fd13733499963d3e184fffbb004d26ba624de8/src/SFML/Window/Window.cpp: In member function ‘void sf::Window::setState(sf::State)’:
/home/dan/Desktop/SFML-22fd13733499963d3e184fffbb004d26ba624de8/src/SFML/Window/Window.cpp:379:22: error: ‘State’ is not a class or namespace
         if (state == State::Windowed)
                      ^
/home/dan/Desktop/SFML-22fd13733499963d3e184fffbb004d26ba624de8/src/SFML/Window/Window.cpp:385:22: error: ‘State’ is not a class or namespace
         if (state == State::Fullscreen)
                      ^
/home/dan/Desktop/SFML-22fd13733499963d3e184fffbb004d26ba624de8/src/SFML/Window/Window.cpp: In member function ‘sf::State sf::Window::getState() const’:
/home/dan/Desktop/SFML-22fd13733499963d3e184fffbb004d26ba624de8/src/SFML/Window/Window.cpp:404:42: error: ‘State’ is not a class or namespace
     return m_impl ? m_impl->getState() : State::Windowed;
                                          ^
src/SFML/Window/CMakeFiles/sfml-window.dir/build.make:374: recipe for target 'src/SFML/Window/CMakeFiles/sfml-window.dir/Window.cpp.o' failed
make[2]: *** [src/SFML/Window/CMakeFiles/sfml-window.dir/Window.cpp.o] Error 1
CMakeFiles/Makefile2:170: recipe for target 'src/SFML/Window/CMakeFiles/sfml-window.dir/all' failed
make[1]: *** [src/SFML/Window/CMakeFiles/sfml-window.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....

Title: Re: Window state
Post by: Foaly on February 21, 2018, 05:14:38 pm
Huh thats weird... It seems like the compiler can't find State in Window.cpp eventough WindowState.hpp is included in Window.hpp...

What compiler/operating system + versions are you using?

As a fix you could try including WindowState.hpp in Window.cpp and see if it compiles.

Also than you for giving this a try!  :)
Title: Re: Window state
Post by: Recoil on July 20, 2019, 04:24:57 am
Sorry to necro this post, and I know it is over a year old, but has there been any update to implementing minimize and maximize states?  My Google-fu has failed to find a working implementation of doing this programmatically.

I'm creating a borderless render window, and using a custom form that can be skinned (with a theme soon).  I can get the close button to work, and if this was a windows form I could go that route, but I am using .NET Core and this functionality does not exist.  I can clunkily maximize the render window, but there is no option to set the visibility = false and keep the icon in the taskbar for setting back to visibility = true.
Title: Re: Window state
Post by: eXpl0it3r on June 07, 2020, 08:16:47 pm
Going over the proposed API and discussion again, I was wondering, whether it would make sense to have a sf::State::Hidden?
That way we have two sets of window "modifiers": states and styles
Styles define what the window decorations look like (titlebar, buttons, borderless, etc.) and states define the state of the window (window, fullscreen, minized, maximized and hidden).
That would also mean, that in theory we could deprecate setVisible().

On the other hand, this would make adding sf::Style::Hidden so we can construct a window in a hidden state a bit of a confusing design, as you'd have hidden on style and state...
Maybe keeping setVisible for SFML 2 and creating windows hidden by default in SFML 3 would be a trade off here.

Either way, I've started to put together all the relevant points as a sort of "solution design" on the wiki. That should help bring together all the current discussion points, implementations and API checks, plus it can help as future reference.
https://github.com/SFML/SFML/wiki/SD%3A-States-and-Styles