Open kettle11 opened 4 years ago
Unless I'm mistaken, "borderless fullscreen" involves making the window borderless and then scaling the window to fill up the whole screen? In this case, do we want to store the window position and size when borderless fullscreen is activated so that we can actually restore the window? or should we just let the user handle it? If we were going to let the user handle it anyway, can't we just implement borderless and call it a day?
AFAICT in Windows, borderless is achieved by setting the window style to WS_POPUP | WS_VISIBLE
.
I think the reason I hesitated on this is that MacOS is different than Windows and I wasn't sure what to call things and how to reconcile options.
After some investigation here's my thoughts:
Borderless-fullscreen is mostly a useful feature on Windows because with true-fullscreen it can be hard to alt-tab or swap to another program quickly. I think this is in part because Windows actually does special things to give true full-screen app more direct rendering access.
On Mac true-fullscreen doesn't do anything special (as far as I know) so it still behaves nicely and allows alt-tabs and all that. The only annoyance (for games) is that the dock and menubar can show up when the mouse moves near the top or bottom of the screen. (This API needs to be used somewhere in kapp
to prevent that: : https://developer.apple.com/documentation/appkit/nswindowdelegate/1419144-window?language=objc)
So a "true" borderless full-screen implementation on Mac would feel awkward and non-native and not really solve any goal.
Quickly launching a Unity game on Mac shows that they treat "borderless fullscreen" and "fullscreen" the same as far as I can tell.
There's also some winit
discussion about the issue here: https://github.com/rust-windowing/winit/issues/1195
As for what to do I'm going to think about it. Do you have thoughts?
That makes sense. So then, how about something like this? a) Have a fullscreen_borderless function that just calls fullscreen() on Mac b) In the Windows implementation of fullscreen_borderless, store the window position and size, set some flag to mark the window as "borderless fullscreen" c) In the Windows implementation of restore_window, go back to the window position and size stored in step b if the flag was set
This would introduce even more "overhead" (really, I'm sure the runtime overhead of setting some numbers is minimal, I guess it's more about the ugly static mut
atomics lying around everywhere) for the Windows implementation, but I can't think of any other way to satisfy the fullscreen needs on Windows.
That sounds great!
And yeah the overhead of storing some numbers is trivial.
One thing is I have been trying to keep multiple windows working even if it's not an explicit promise of kapp
. Adding static mut
s that are specific to one window would break that. Probably each window should store its own extra data specific to kapp
.
Various techniques for that are discussed here: https://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc
Ah, right, multiple windows. Sorry, that completely escaped my mind. That link seems to suggest the only "correct" way to store window-specific data here is to have a HashMap<HWND, Option<WindowState>>
where struct WindowState { x: u32, y: u32, width: u32, height: u32 }
or something (arbitrary nomenclature for the struct). Does that sound OK?
One issue with this approach: assuming we expose an API for setting borderless, the user could manually "restore" the window. Then, if they, say, exclusive fullscreen the window and then restore it, the window will assume its position/size from before the initial fullscreen_borderless call. We need to set the Option
to None when borderless
is set to false or when the window size/position is modified. Somewhat messy :(
A HashMap with HWND
as the key sounds good to me.
One issue with this approach: assuming we expose an API for setting borderless, the user could manually "restore" the window.
If I'm following correctly then I don't think we should worry about the user doing weird things like this. If it simplifies kapp
code to ignore clearly strange usage of the API then we should do that. If people run into issues then they can report an issue.
We also could choose to ignore calls to set_window_size
when fullscreen because resizing a window when fullscreen doesn't make sense anyways.
@MasonRemaley wrote-up a really good investigation of full-screen support on Windows: https://www.anthropicstudios.com/2021/02/20/fullscreen-exclusive-is-a-lie/
Their conclusion is that exclusive full screen support is spotty across games. This is leading me to think that kapp
shouldn't try to support exclusive fullscreen (at least initially). It's a "nice to have" but not "need to have" feature for most applications.
If that's the case, could we just have one fullscreen()
function (at least initially) that does borderless fullscreen on Windows and normal fullscreen on other platforms? We could simply ignore any calls to set_borderless
or set_window_size
while fullscreen.
Yup, that seems like the best call. Easy to get right without hacks and covers most use cases.
Borderless fullscreen is a useful and common feature for games.
Investigation is needed to find common implementations for Windows and MacOS.