Skip to content
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

[core] Fullscreen without video mode change #3378

Closed
M374LX opened this issue Oct 5, 2023 · 16 comments
Closed

[core] Fullscreen without video mode change #3378

M374LX opened this issue Oct 5, 2023 · 16 comments

Comments

@M374LX
Copy link
Contributor

M374LX commented Oct 5, 2023

Update: in fact, what makes it difficult for raylib to properly implement fullscreen without a video mode change is GLFW's lack of a function that just makes the window fullscreen and lets the window manager do the rest without touching the video mode.

Issue description

Problems with an incorrect resolution when toggling fullscreen mode have been reported in #3099. However, according to the GLFW documentation at https://www.glfw.org/docs/latest/window_guide.html#window_windowed_full_screen, "If the closest match for the desired video mode is the current one, the video mode will not be changed, making window creation faster and application switching much smoother".

The same effect can be achieved in SDL2 by calling SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); (with SDL_WINDOW_FULLSCREEN_DESKTOP instead of SDL_WINDOW_FULLSCREEN).

With a borderless window, as implemented in #3216, there is still a problem: the window is movable (noticeably on a window manager that allows moving a window while holding a key, like dwm from https://suckless.org).

Fullscreen toggling without a video mode change can be implemented in GLFW like so:

const GLFWvidmode* mode = glfwGetVideoMode(monitor);

glfwSetWindowMonitor(window, monitor, 0, 0, mode->width, mode->height, mode->refreshRate);

As we can see, we need to pass the refresh rate along with the width and height of the monitor to glfwSetWindowMonitor().

In https://github.com/raysan5/raylib/blob/bc15c19518968878b68bbfe8eac3fe4297f11770/src/rcore.c#L1222C37-L1222C37, we have GLFW_DONT_CARE instead of the actual refresh rate, but I don't think this should be changed, as it is possible that a programmer using raylib actually wants a video mode change and the monitor does not support the same refresh rate on a different video mode.

Some of the possible approaches to implement fullscreen toggling without a video mode change include:

  1. Use FLAG_FULLSCREEN_MODE and ToggleFullscreen(), but pass the refresh rate to glfwSetWindowMonitor() when the screen size corresponds to monitor but GLFW_DONT_CARE otherwise.
  2. Create a new flag, like FLAG_FULLSCREEN_DESKTOP_MODE, and a new function, like ToggleDesktopFullscreen(). This one could automatically use the monitor size and free the programmer from the need to call SetWindowSize() before toggling fullscreen mode.
  3. Use FLAG_FULLSCREEN_MODE and ToggleFullscreen(), but create a new flag, like FLAG_FULLSCREEN_DESKTOP, to specify that a video mode change should not happen.

Environment

Linux

@M374LX M374LX changed the title [rcore] Fullscreen without mode change [core] Fullscreen without mode change Oct 5, 2023
@M374LX M374LX changed the title [core] Fullscreen without mode change [core] Fullscreen without video mode change Oct 5, 2023
@ghost
Copy link

ghost commented Oct 5, 2023

@M374LX It's been a few months, but I vaguely remember something about glfwSetWindowMonitor() forcing fullscreen, fullscreen getting minimized when alt-tabbing and a lot of multimonitor and refresh/timing issues. Which, from memory, were the reasons why FLAG_BORDERLESS_WINDOWED_MODE was implemented that way.

Did you successfully implement it with a single glfwSetWindowMonitor() call?

@M374LX
Copy link
Contributor Author

M374LX commented Oct 5, 2023

@ubkp Not yet tested extensively, but it worked well on a quick test with a single monitor in which the refresh rate was passed to glfwSetWindowMonitor() instead of GLFW_DONT_CARE.

@ghost
Copy link

ghost commented Oct 5, 2023

@M374LX Unless I'm missing something, GLFW_DONT_CARE shouldn't be much of problem, quoting the documentation:

"GLFW_REFRESH_RATE specifies the desired refresh rate for full screen windows. A value of GLFW_DONT_CARE means the highest available refresh rate will be used. This hint is ignored for windowed mode windows."

But regarding a single glfwSetWindowMonitor(), does it get minimized if you Alt Tab out of it?

@M374LX
Copy link
Contributor Author

M374LX commented Oct 6, 2023

@ubkp On Openbox, the window does not get minimized with Alt+Tab, but is loses focus and the new focused window is displayed over it. The same happens with SDL when using SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);.

I have also just added a third approach to the issue description.

@ghost
Copy link

ghost commented Oct 6, 2023

@M374LX If it doesn't trigger the window to get minimized, then that could be a nice replacement for ToggleBorderlessWindowed().

Do you want to send a PR? Or should I review it here?

@M374LX
Copy link
Contributor Author

M374LX commented Oct 6, 2023

Creating a draft PR is in my plans.

@ghost
Copy link

ghost commented Oct 6, 2023

@M374LX Excellent!

Suggestion: see if you can integrate it on ToggleFullscreen()/FLAG_FULLSCREEN_MODE if the WindowSize is the same as MonitorSize.
(Edit: actually, considering "If the closest match for the desired video mode is the current one, the video mode will not be changed,[...]", wouldn't setting WindowSize to MonitorSize before calling ToggleFullscreen() do that already?)
Edit 2: see next comment.

If that gives you trouble, option 2 is probably the safest alternative.

Also, if possible, test it on a multimonitor configuration.

@ghost
Copy link

ghost commented Oct 6, 2023

@M374LX Tested this scenario: "If the closest match for the desired video mode is the current one, the video mode will not be changed,[...]" by setting WindowSize to MonitorSize before calling ToggleFullscreen():

#include "raylib.h"

int main(void) {

InitWindow(800, 450, "test");
SetWindowState(FLAG_WINDOW_UNDECORATED);
SetWindowState(FLAG_WINDOW_TOPMOST);
SetTargetFPS(60);

    while (!WindowShouldClose()) {

    if (IsKeyPressed(KEY_F1)) { 
        SetWindowPosition(0,0);
        SetWindowSize(GetMonitorWidth(0), GetMonitorHeight(0));
    }

    if (IsKeyPressed(KEY_F2)) { 
        ToggleFullscreen();
    }

    BeginDrawing();
    ClearBackground(RAYWHITE);
    DrawText("Press F1, then F2.", 10, 10, 20, BLACK);
    EndDrawing();
    }

    CloseWindow();
    return 0;
}

Unfortunately, when alt-tabbing, it causes the window to get minimized here on Gnome (Fedora 38 64-bit). I remember it also would cause the window to get minimized on MATE (Mint 21.1 64-bit). So that solution may actually require some testing.

Edit 1: clarification.
Edit 2: updated code just to be sure the window decoration, level and position were not affecting it, but, unfortunately, same alt-tabbing causing it to get minimized issue.

@raysan5
Copy link
Owner

raysan5 commented Oct 8, 2023

@M374LX Sorry, I'm a bit lost with this improvement, why is it needed considering ToggleBorderlessWindowed() is already available and working?

@M374LX
Copy link
Contributor Author

M374LX commented Oct 8, 2023

Mainly because a borderless window is still movable.

@raysan5
Copy link
Owner

raysan5 commented Oct 8, 2023

Mainly because a borderless window is still movable.

What's the problem with that?

@M374LX
Copy link
Contributor Author

M374LX commented Oct 8, 2023

Don't you agree that a window occupying the entire screen, be it fullscreen or borderless, should stay at position (0, 0)?

We could try to check if the window position is not (0, 0) (possibly in EndDrawing()) and automatically move it to (0, 0) if it is not, but the window will probably shake when the user tries to move it.

@ghost
Copy link

ghost commented Oct 9, 2023

Don't you agree that a window occupying the entire screen, be it fullscreen or borderless, should stay at position (0, 0)?

  1. They do that (L364; L448-L453), but any window (or dialog) on Linux is always be at the mercy of the Window Manager control. It can (and will) do whatever it wants with the window (move it, resize it, minimize it, maximize it, etc). Specially highly customizable WMs (like Fluxbox, Openbox, etc) and, notoriously, Tiling Window Managers that will always do whatever they want with the windows they manage.

We could try to check if the window position is not (0, 0) (possibly in EndDrawing()) and automatically move it to (0, 0) if it is not, but the window will probably shake when the user tries to move it.

  1. Could we please not mess the drawing pipeline. This can introduce so many problems. One use case on Linux should not warrant this much refactoring.

  2. Yet again, the only thing that should be fixed is SetWindowSize to update CORE.

@raysan5
Copy link
Owner

raysan5 commented Oct 9, 2023

At this point I'm quite lost with all those fullscreen issues and PR, I highly agree with all the @ubkp comments and I prefer to avoid any redesign and overengineered implementation looking for problems that hardly ever occur.

@M374LX
Copy link
Contributor Author

M374LX commented Oct 10, 2023

Here are the differences:

  • Fullscreen with mode change - the window manager treats the window as fullscreen and thus prevents it from being moved, but a video mode change happens and the screen blanks out for a second in the process.
  • Fullscreen without mode change - the window manager treats the window as fullscreen and thus prevents it from being moved, with no video mode change and the window becoming fullscreen instantly. It should behave the same way as SDL_WINDOW_FULLSCREEN_DESKTOP (if not identically, as close as possible).
  • Borderless - an imitation of a fullscreen window without a mode change, but the window is not treated as fullscreen by the window manager.

@raysan5
Copy link
Owner

raysan5 commented Oct 26, 2023

I'm closing this issue, discussion can be probably continued on #3390

@raysan5 raysan5 closed this as completed Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants