True borderless fullscreen behaviour

Here’s the problem, I initialise my window as a normal window, then upon a certain keypress I call SDL_SetWindowFullscreen(fb.window, SDL_WINDOW_FULLSCREEN_DESKTOP);, which switches to fullscreen. Except it doesn’t work quite as it should. Here’s what it does:

-Flash both screens to black
-Set it to fullscreen on the main screen (as desired)
when I click on the secondary screen (where let’s say I have a web browser open):
-Flashes both screens to black again
-My SDL window disappears from the main screen (which it shouldn’t) and what is shown (the other programs in the background) has compositing issues, like GUI elements being black (apparently a normal Windows compositing bug related to having something in fullscreen)
when I switch back to my SDL program:
-Black flash again from switching to fullscreen (but not as bad as when you use true fullscreen)
-Compositing on the secondary screen is all screwed up and stays really screwed up until I switch back out of my SDL program

My point is this doesn’t behave like a true borderless window fullscreen mode in which the switch between programs is seamless. The way it currently works isn’t it, it’s some kind of fullscreen mode. So how can I obtain the desired behaviour? Not using SDL_SetWindowFullscreen() and instead using SDL_SetWindowResizable(), SDL_SetWindowBordered(), SDL_SetWindowPosition() and SDL_SetWindowSize() to the screen’s size give the same result, it seems that if you try to make a borderless window that is the size of the screen then it switches to a fullscreen mode even though that’s specifically what I don’t want.

I’m using OpenGL on Windows 7 with SDL 2.0.8.

Does it work if you create the window as fullscreen from the beginning?

I just tried initialising with the flags SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_OPENGL in SDL_CreateWindow() and the problem is the same.

Try SDL_WINDOW_FULLSCREEN instead.

It’s worse since it does the resolution switching thing (even though the resolution doesn’t change).

Ok, but does it still turn the other monitor black?

Yes.

(Okay this is ridiculous but this thing won’t just let me reply with “Yes” because it’s not enough characters.)

Ok, so I tried an older application on mine and I used: window=SDL_CreateWindow(“1 million particles”, 100, 100, windows_x_len, windows_y_len, SDL_WINDOW_FULLSCREEN_DESKTOP);

I got an effect similar to what you described, but not the same. The app was full screen on my main monitor, and the other monitor was left alone. However I think there might have been a problem with the mouse coordinates.

When I clicked on the other monitor, the app window was minimized, but when I clicked back on the taskbar it went back to full screen mode.

I bet not everyone has the same compositing glitches as I have, but it says something about how the fullscreen mode is achieved (for instance it depends on games, though these days most games do it properly). A way to do it manually is like this:

SDL_SetWindowResizable(fb.window, SDL_FALSE);
SDL_SetWindowBordered(fb.window, SDL_FALSE);
SDL_SetWindowPosition(fb.window, 0, 0);
SDL_SetWindowSize(fb.window, sdl_get_display_dim(0).x, sdl_get_display_dim(0).y);

If you use the screen resolution in the SDL_SetWindowSize() call then it’s as if using SDL_WINDOW_FULLSCREEN_DESKTOP, however if you set a smaller size then you get the proper result, which is a borderless window (but obviously that doesn’t take up the full screen) that doesn’t do any of the glitches mentioned. So there’s definitely something being done when the window dimensions are detected to be those of the screen resolution.

I am now on Windows 10 and while I don’t have flashes or compositing problems anymore I can confirm that it also minimises itself when I click on the second screen outside of my SDL app. This is pretty inconvenient, I can’t find a way to change that behaviour.

Have you tried SDL_SetWindowBordered(fb.window, SDL_TRUE); with position and size set to the display bounds? This alleviated an issue I had with D3D, but I can’t speak for or test OpenGL at the moment.

(On D3D, the border + border shadow only shows on adjacent monitors.)

1 Like

Wow it works! Just one thing though, how do you go back to windowed mode properly after doing this? SDL_SetWindowFullscreen(fb.window, 0); won’t do it and the only way I can think of doing it is by individual calls to SDL_SetWindow(Resizable/Bordered/Position/Size) with saved values, which isn’t great.

Oh it’s no big deal but I was hoping that there would be a simpler way than me storing and restoring all those parameters myself.

In case it helps anyone here’s my code https://github.com/Photosounder/rouziclib/blob/4ee89fe8f4067507797e901012f0945a0f757e42/rouziclib/libraries/sdl.c#L540 (it’s not self-contained so I can’t just copy-paste it all).

So before switching to fullscreen I store the rectangle of the window, then set the window to be the rectangle of the display that has the largest area of the window. And when turning it off I restore the stored rectangle of the window. Works pretty smoothly for me and my algorithm for determining which display to go fullscreen on seems to match the Windows 10 way of determining which monitor’s task bar to put the window into.

I’m able to get actual fake fullscreen by using SDL_CreateWindow without fullscreen flags and the native resolution returned by SDL_GetDesktopDisplayMode. Don’t know how applicable this is to SDL_SetWindowResizable/SDL_SetWindowSize or whether or not it’s something that can be relied on to always work.

edit: Even with this method windows created with SDL_WINDOW_OPENGL appear to switch to regular fullscreen until focus is removed. While unfocused they switch to behaving like fake fullscreen windows (with a noticable screen blink when this happens). Windows that draw through a (direct3d) SDL_Renderer or SDL_GetWindowSurface will always act like fake fullscreen.

It’d be nice to have a flag that is unambiguously intended to be (and actually produces) fake fullscreen.

This is an issue caused by Windows changing its behavior.
One of the new “features” is that Windows will detect whether your window is a borderless fullscreen window, and if so, make it behave more like exclusive fullscreen.
This is mentioned in https://www.youtube.com/watch?v=E3wTajGZOsA 4:47-5:02 “In Windows 8, we enabled a new feature which is called directflip. The way directflip works is that the compositor will detect that your window covers the entire screen and will actually decide not to compose.”. After that, more changes are described, including that these changes give windows the ability to suffer screen-tearing.

My solution to this problem is to create a window in windowed mode with a size 1 pixel taller than fits on the display, with border turned off. Because the window size doesn’t exactly match the display, Windows wont mess with your window. And because it’s bigger than the display, no content is lost.

2 Likes

Interesting, thank you. I guess that explains it. But my code works around the problem neatly without having to add 1 pixel (which might cause problems in a few ways), maybe you should look into that :wink:

I experimented a bit more, comparing your window configuration to mine, and in my case enabling the border also prevents the issue from occurring. However, this is not an acceptable solution for me, as this border would then be visible to adjacent displays. On Windows 10 it’s not so bad as the border is very thin, but on other operating systems, like Windows 7, it is much thicker.
That’s not to say my solution is perfect either. The work around of “extend window by 1px” only works if there’s space to do so. If the display the window is on is fully surrounding by other displays, then the window would bleed 1px onto adjacent displays. Not to mention it requires work-around code to function correctly in terms of render and mouse position.