-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[rcore] Window Mode Overhaul #4147
Comments
@raysan5 @SuperUserNameMan @JeffM2501 Please add any ideas, suggestions, etc ;) |
Ok, I'm a little confused because i don't know in which issue/thread/conversation to begin, so i'm randomly picking this one. I think i need to clarify some logic first. (at least to myself), and see if we all agree.
On the other hand, making
Problem : if the resolution provided in To recapitulate : (i hope no reader is colorblind)
edit : note that desktops games like So, my point is that if we take relevant and irrelevant use-case scenario into account, we could simplify our expectation from current implementation, and identify what are real issues that need to be fixed, and what are wrong issues that need the user to clarify the purpose of their project and their expectation. What do you think ? |
Why would |
From a logical perspective, it's because a desktop app is meant to work in the desktop, with other desktop apps. When a desktop app needs to use the maximum available screen space, it is either maximized, or set to a maximized borderless window (like a "no distraction mode"). On the other hand, If you write a 3D editor, or a "3D model poser", or a "chiptune editor", or a desktop game, or whatever desktop app, you don't need an exclusive access to the display. Miximized window or "no distraction mode" ( edit: an exception would be an app that is a "game editor" that might allow the user to "run" the edited game into exclusive fullscreen mode ... but as mentioned below, the DPI rescaling of text and UI could be done by code using Also, from a technical point of view, if your desktop is in HDPI mode, you'd probably want the UI and the text of your app to be rescaled accordingly to the DPI.
The problem is that using |
Note that if |
I also didn't know where to begin, so I just put it all out there :) I think the first thing we need to do (what you already started) is to get on the same page and agree on what is actually needed. So starting with this issue is probably best. I agree with your assumptions I just need some clarification on the
Here the closest resolution is picked on initialization from the supported resolutions from GLFW. In any case does this circumvent the problem with not knowing what GLFW would pick for a resolution?
I don´t think this is a good idea? Again raylib would do something under the hood that is hard to understand. Should There is also the solution to this entire problem of opening the system up and let the user implement the window handling for themselves? At least as an option? Because this might also be a case where it is impossible to meet all the needs of everyone using raylib. |
There is still this issue for
Also should the resizable flag be cleared automatically when As for now all these flags are linked in some way regarding window handling:
We could seperate those flags into window modes and supported flags.
Random Idea?Raylib could put its own system on top hiding the current way of having config flags and window modes mixed? Example:
I have no idea if that makes sense or is usable 😅 |
IMO, with current implementation, it is better, because you increase your chances to actually get a standard full screen resolution when toggling to exclusive full screen mode. If i ask 800x800, i get 800x600 SVGA. If i ask 640x480 or 800x600 or 1024x768 or 1280x720, i get what i want because they are standard hardware reso that are commonly supported by most hardware.
Because the display hardware resolution will remains unchanged. It will remains the desktop resolution.
I haven't found any function that allows this in current Raylib API.
If we request a hardware resolution that has a width or height greater than our content resolution, we would have to rescale the content to fit without changing its aspect ratio, to center it, and to add black rectangles on the empty sides. It might also mean that Raylib would have to render to a texture instead of rendering directly to the window's surface, unless there are some Alternatively, all of this could be done "manually" by the programmer in the application code side by rendering to a texture.
3 parameters : Like you mentioned somewhere before, we'd need a function that allow enumerating the list of supported hardware resolution and refresh rates so we could let the end-user choose in which hardware resolution they want to run the program.
Anyway there is no point in activating HIGHDPI if the app is intended to run in exclusive fulllscreen mode. So, i think that if the programmer want both HDPI and fullscreen, they actually need maximized borderless window.
With a function that would allow to enumerate supported hardware resolution, this could be a greater step forward already. Also, I think |
I think "meant" is too strong here. I play AAA Desktop applications, and some of them take the full screen, others offer different configurations, but usually not windowed in the way you mean it. I have one graphical application that I have to use "reduced" in order to shrink the vertical enough so that the OS pop-up task bar does not interfere with it. Other than that, I fill my screen with it. @SoloByte PS: Some of the effects being noticed have to do with monitors having built-in scaling provisions for particular dimensions (in pixels). Graphical drivers may rely on that. You can usually see what's available in various situations where the different frame sizes (in pixels) are shown as options. The best cinematic-quality game software tends to exploit that. There may also be accessibility considerations here, but I have no idea how that is handled in quality software. |
I think "meant" is too strong here. I play AAA Desktop applications, and some of them take the full screen, others offer different configurations, but usually not windowed in the way you mean it. I have one graphical application that I have to use "reduced" in order to shrink the vertical enough so that the OS pop-up task bar does not interfere with it. Other than that, I fill my screen with it. |
@SoloByte PS: Some of the effects being noticed have to do with monitors having built-in scaling provisions for particular dimensions (in pixels). Graphical drivers may rely on that. You can usually see what's available in various situations where the different frame sizes (in pixels) are shown as options. The best cinematic-quality game software tends to exploit that. There may also be accessibility considerations here, but I have no idea how that is handled in quality software. |
Thank you :) I will keep that in mind 👍 |
A little side note Currently those 4 flags have to be set before
If they can only be set with the I can open a seperate issue for this as well if it is considered a good idea ;) |
@SoloByte |
Yes it has to be set before InitWindow like I said above ;) My idea is to have init window set them internally before initializing the window. |
I think you'd better call that Then there's a matter of explaining this to users of the raylib API. That is, how do they determine how to set it. In particular, how does one create a distributable desktop program that determine the proper situation on a given computer at run-time and also when monitors are adjusted or switched? I think some clear use cases and what to do with them need to be considered. |
Absolutely. It could also be done differently. For me personally it was always confusing which flags actually have to be set before init window. Once I knew it I would forget it again in a couple of months and had to figure it out again ;)
Those 4 flags I mentioned can´t be changed after My goal would be to clean up the config flags a bit with the window mode overhaul if possible. For me there a 3 possible ways that I would like regarding window handling in raylib:
|
Well, if you define desktop app to be "non-fullscreen" then obviously it doesn't need
Yet, such as interpretation of
Again, this links to my remarks above on the meaning of the function names above. I would never assume |
I agree that the names of the functions themselves are relatively imprecise. But that's what we have to deal with for the sake of backward compatibility. And that's also why I interpreted the intention of the functions according to their current source code implementations in the main GLFW platform backend.
On the other hand, Beyond that, there a consequences to take into consideration.
So, with current Raylib GLFW backend implementation, i think the programmer needs to be aware that they might not be able to use all features altogether, and that some are better suited for certain type of project, etc. Of course, it is absolutely possible to rewrite the window management system of Raylib to make an universal solution that would just work out of the box without surprise, and without prior knowledge of what happens under the hood. I don't know how long it would take to be ready, but I personally don't want to wait or spend too much energy and time into it. |
@paulmelis I wonder about the nomenclature also. Earlier today I opened one of the older AAA games I have (Assassins Creed Origins) and checked its options for Window Mode: They are "Full Screen," "Windowed," and "Borderless." There are few variations on this. I have seen "Full Screen (Windowed)" on occasion. None of these are explained. I always just go for Full Screen. I suppose my point is that this is at the end-user level, and I can change those settings even with the game running but paused, although I usually go to such options just after start-up, as when I have installed a new monitor. |
If i had to extend current Raylib API without breaking backward compatibility, I'd add these functions that could simplify the life of beginners and prototypers : // Open a resizable window with a content surface of a fixed dimension
// that is rescaled and centered with black borders if required
void InitWindowWithFixedContentSize( int windowWidth , int windowHeight, int contentWidth, int contentHeight );
// Change the monitor resolution and display the window's content
// upscaled and centered with black borders if required
bool ActivateFullscreenExclusiveMode( int monitor, int width, int height, int refreshRate );
// Like above, except that the resolution of the monitor is kept unchanged
bool ActivateFullscreenDesktopMode( int monitor );
// Restore windowed mode
void RestoreWindowedMode();
// And to work with ToggleFullsceenExclusiveMode() :
int GetMonitorSupportedResolutionsCount( int monitor );
Resolution GetMonitorSupportedResolution( int monitor, int resolutionIndex ); |
For me this call does something slightly different: the window doesn't end up covering the full desktop, but leaves the MATE menu bar at the top uncovered. I need to set the window position to (0,0) after the call to get full desktop coverage:
However, when
Edit: accidentally submitted the comment before I was finished |
@paulmelis : yes, i have similar issue too #4149 on my LinuxMint + MATE, except that the first call covers the whole desktop including the menu bar at the bottom on mine. |
Ah, good catch, interesting comments on GLFW in that issue |
It does the same on macOS. It leaves the top bar uncovered.
I will test that on macOS and see what it does. |
It should move the window to the specified monitor if the window is currently on a different monitor. How should the refresh rate be handled regarding vsync? Should/Does
This function therefore sets the window size to the size of the specified monitor? (If a different resolution is required It should also move the window to the specified monitor if the window is currently on a different monitor. The bool return value tells you if the request was successfull? |
Well, i'm not sure where you see a problem, because in my mind, when From the programmer perspective, only the interaction of vsync with Regarding
Yes, i think it is particularly relevant with edit : despite the lazy programmer might not even check the boolean ... |
I think this point is very important because currently exiting fullscreen does not properly restore window mode.
Yes, I see it the same way. I am asking because currently (at least for me) vsync and fullscreen mode do not work well together. (choppy framerate that is lower than it should be) The refresh rate parameter:
I am just trying to be overly clear so we don´t end up talking about different things were one side asumes something that the other side does not :)
But it is still important because the current implementation does not tell you anything 😉 |
Maybe that would depend on how this fullscreen desktop mode would be implemented. Obviously, we could not replicate what is currently done in So, instead of trying to maximize an oversized and undecorated window, we could ask GLFW to do an hardware fullscreen of the same resolution and refresh rate that is currently active on the monitor. I quickly tested that approach yesterday. But I only tested with the main monitor, so i don't know if the desktop remain visible on secondary monitors, or if it is turned off (like back in the old time ways). Also, the problem with this approach is that it seems to be incompatible with
This one function is to set the frequency of the main loop by software (if i understood correctly). The programmer might want to set it to very low frequency for various reasons, like debugging purpose, or special effects, or to change the frequency of the program.
Not safe, since
In that case, the programmer might want to |
Note : there is also this compilation option to take into account : Note 2 : maybe we should also take other platform backends into consideration regarding their ability to implement what GLFW could. |
I have tested this with glfw directly and implemented a borderless fullscreen with Beware it is c# again :)
Editwith this change
it also work perfect on multiple monitors with different resolutions. It restores the window to the monitor it was on before fullscreen was entered. |
You have no mercy for my delicate eyes ..... |
Ok, back again (false alarm, i pressed the wrong key in my test example) I confirm it works like a charm on my Linux system with dual screen. Here is the new candidate : // Toggle borderless windowed mode
void ToggleBorderlessWindowed(void)
{
// Leave fullscreen before attempting to set borderless windowed mode and get screen position from it
bool wasOnFullscreen = false;
if (CORE.Window.fullscreen)
{
CORE.Window.previousPosition = CORE.Window.position;
ToggleFullscreen();
wasOnFullscreen = true;
}
const int monitor = GetCurrentMonitor();
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
{
const GLFWvidmode *mode = glfwGetVideoMode(monitors[monitor]);
if (mode)
{
if (!IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE))
{
// Store screen position and size
// NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
if (!wasOnFullscreen) glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);
CORE.Window.previousScreen = CORE.Window.screen;
// Get monitor position and size
glfwSetWindowMonitor(platform.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate);
// Let's not wait for GLFW to call WindowSizeCallback to update these values :
CORE.Window.screen.width = mode->width ;
CORE.Window.screen.height = mode->height ;
// Refocus window
glfwFocusWindow(platform.handle);
CORE.Window.flags |= FLAG_BORDERLESS_WINDOWED_MODE;
}
else
{
// Return previous screen size and position
int prevPosX = CORE.Window.previousPosition.x ;
int prevPosY = CORE.Window.previousPosition.y ;
int prevWidth = CORE.Window.previousScreen.width ;
int prevHeight = CORE.Window.previousScreen.height ;
glfwSetWindowMonitor(platform.handle, NULL, prevPosX , prevPosY, prevWidth, prevHeight, GLFW_DONT_CARE);
// Let's not wait for GLFW to call WindowSizeCallback to update these values :
CORE.Window.screen.width = prevWidth ;
CORE.Window.screen.height = prevHeight ;
// Refocus window
glfwFocusWindow(platform.handle);
CORE.Window.flags &= ~FLAG_BORDERLESS_WINDOWED_MODE;
}
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find video mode for selected monitor");
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
} edit: code updated according to the documentation : https://www.glfw.org/docs/latest/group__window.html#ga81c76c418af80a1cce7055bccb0ae0a7 edit2 : update |
work like a charm, only if |
We could now fix the If fullscreen stores prev screen size as well you would could change this here as well.
New functions for proper fullscreenI just hacked them together real quick ^^ void RestoreWindowWindowed()
{
if(CORE.Window.fullscreen || CORE.Window.borderlessFullscreen)
{
// Return previous screen size and position
int prevPosX = CORE.Window.previousPosition.x ;
int prevPosY = CORE.Window.previousPosition.y ;
int prevWidth = CORE.Window.previousScreen.width ;
int prevHeight = CORE.Window.previousScreen.height ;
glfwSetWindowMonitor(platform.handle, NULL, prevPosX , prevPosY, prevWidth, prevHeight, GLFW_DONT_CARE);
// Let's not wait for GLFW to call WindowSizeCallback to update these values :
CORE.Window.screen.width = prevWidth ;
CORE.Window.screen.height = prevHeight ;
// Refocus window
glfwFocusWindow(platform.handle);
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;
}
else TRACELOG(LOG_WARNING, "GLFW: Fullscreen or Borderless Fullscreen are not active.");
}
void SetWindowFullscreen(int monitor, int x, int y, int w, int h, int refreshRate)
{
if(CORE.Window.fullscreen)
{
TRACELOG(LOG_WARNING, "GLFW: Fullscreen already enabled");
return;
}
// Leave borderless fullscreen before attempting to set fullscreen mode and get screen position from it
bool wasOnBorderlessFullscreen = false;
if (CORE.Window.borderlessFullscreen)
{
CORE.Window.previousPosition = CORE.Window.position; // is this necessary? because previous position should be correct from enabled borderless fullscreen
ToggleBorderlessWindowed(); //Could also use -> RestoreWindowedWindow()
wasOnBorderlessFullscreen = true;
}
int monitorCount;
GLFWmonitor **monitors = glfwGetMonitors(&monitorCount);
if ((monitor >= 0) && (monitor < monitorCount))
{
// Store screen position and size
// NOTE: If it was on borderless fullscreen, screen position & size was already stored, so skip setting it here
if (!wasOnBorderlessFullscreen){
glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);
CORE.Window.previousScreen = CORE.Window.screen;
}
glfwSetWindowMonitor(platform.handle, monitors[monitor], x, y, w, h, refreshRate);
// Let's not wait for GLFW to call WindowSizeCallback to update these values :
CORE.Window.screen.width = w ;
CORE.Window.screen.height = h ;
// Refocus window
glfwFocusWindow(platform.handle);
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;
}
else TRACELOG(LOG_WARNING, "GLFW: Failed to find selected monitor");
} |
This line should also no longer be necessary when toggle fullscreen properly saves previous position/size. // Store screen position and size
// NOTE: If it was on fullscreen, screen position was already stored, so skip setting it here
if (!wasOnFullscreen)
{
glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);
CORE.Window.previousScreen = CORE.Window.screen;
} This can be changed as well when ToggleFullscreen() properly saves previous position/size |
Ok, let's talk about fixing |
I have added this to the related issues. |
Please, excuse my lack of response on these issues, it's quite overwhelming and I need some time to read through them. In any case, many thanks to all of you for reviewing windowing system and fullscreen. |
Issue Description
If any statements or assumptions on my side are wrong please correct them. Any ideas are welcome to make to window handling in raylib simple, easy, and consistent.
Related Issues
ToggleFullscreen()
not working as expected with HighDPI mode enabled #3972 (comment)ToggleFullscreen()
andToggleBorderlessWindowed()
not working on Linux ? #4140The text was updated successfully, but these errors were encountered: