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

[rcore][desktop_glfw] Reviewed ToggleFullScreen(), ToggleBorderlessWindowed() and FLAG_WINDOW_HIGHDPI issues #4151

Closed
Changes from 9 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
949aa21
should fix `ToggleBorderlessWindowed()` on Linux and Macos
SuperUserNameMan Jul 10, 2024
3f605e3
some code style convention and we should be good
SuperUserNameMan Jul 10, 2024
7ddb880
should fix all issues related to HDPI, fullscreen and bordeless
SuperUserNameMan Jul 10, 2024
21bff48
comment clarification
SuperUserNameMan Jul 11, 2024
a76adf9
little `ToggleFullscreen()` cleanup
SuperUserNameMan Jul 11, 2024
545665d
toggle currently active fullscreen mode and leave
SuperUserNameMan Jul 11, 2024
b004531
immediate access to `GetScreenWidth/Height()`, `GetRenderWidth/Height()`
SuperUserNameMan Jul 11, 2024
1b800a1
explicit focus request in `ToggleFullscreen()`
SuperUserNameMan Jul 12, 2024
32e9d88
`InitPlatform()` set `GLFW_SCALE_FRAMEBUFFER` to false by default
SuperUserNameMan Jul 13, 2024
312f9c2
disable `GLFW_AUTO_ICONIFY` for all fullscreen modes
SuperUserNameMan Jul 15, 2024
dc4c60b
detect Wayland special case at runtime
SuperUserNameMan Jul 15, 2024
3c48b5c
Update raylib.h : add experimental `FLAG_RESCALE_CONTENT`
SuperUserNameMan Jul 17, 2024
a2d1e66
Update rcore_desktop_glfw.c : replace old PR with new branch PR
SuperUserNameMan Jul 17, 2024
2d22514
Merge branch 'raysan5:master' into fix-ToggleBorderlessWindowed
SuperUserNameMan Jul 17, 2024
a2ccd82
CodeQL bot : Variable `result` hides another variable of the same nam…
SuperUserNameMan Jul 17, 2024
05b1720
GLFW : Wayland don't support setting or getting window pos
SuperUserNameMan Jul 20, 2024
b2c9c5e
make `SetWindowMonitor()` works with `FLAG_BORDERLESS_WINDOWED`
SuperUserNameMan Jul 20, 2024
0413845
invalid window size default to 3/4 of the display
SuperUserNameMan Jul 21, 2024
310e4d7
rcore.c - add `CORE.Window.lastAssociatedMonitorIndex` for Wayland
SuperUserNameMan Jul 21, 2024
9fb406a
rcore_desktop_glfw.c - Wayland compatibility
SuperUserNameMan Jul 21, 2024
c5f90a5
`rcore_desktop_glfw.c` : improved Wayland support
SuperUserNameMan Jul 22, 2024
1a7657e
`rcore_desktop_glfw.c` : `SetWindowMonitor()` workaround for Wayland
SuperUserNameMan Jul 22, 2024
1902015
`rcore_desktop_glfw.c` : disable `FLAG_WINDOW_HIGHDPI` on Wayland
SuperUserNameMan Jul 22, 2024
2ffca57
`GetWindowScaleDPI()` return `{1,1}` if HDPI or fullscreen modes
SuperUserNameMan Jul 22, 2024
79316b2
typos
SuperUserNameMan Jul 22, 2024
02ae6e9
`rcore.c` : mouse offset and scaling consistency - part 1
SuperUserNameMan Jul 23, 2024
f3d8fc7
`rcore_desktop_glfw.c` : mouse offset and scaling consistency - part 2
SuperUserNameMan Jul 23, 2024
df62c80
`rcore_desktop_glfw.c` : fix HDPI scaling on Win11 + window restorati…
SuperUserNameMan Jul 23, 2024
02666be
`rcore.c` : typo and cancel premature change merge
SuperUserNameMan Jul 23, 2024
0882f15
`raylib.h` : add flags to control the texture font linear filtering -…
SuperUserNameMan Jul 23, 2024
4ae3e55
`rcore.c` : flags to control texture font linear filtering - part 2
SuperUserNameMan Jul 23, 2024
9228338
`rcore_desktop_glfw.c` : flags to control texture font linear filteri…
SuperUserNameMan Jul 23, 2024
d4ad622
`rcore_desktop_glfw.c` : platform offset and scaling in `SetMousePosi…
SuperUserNameMan Jul 24, 2024
108e3bd
`rcore_desktop_glfw.c` : `IsCursorOnScreen()` does what is says
SuperUserNameMan Jul 24, 2024
eac2e6f
`rcore_desktop_glfw.c` : simplies `SetWindowState()` and `ClearWindow…
SuperUserNameMan Jul 24, 2024
d4f3e1a
Update rcore.c
SuperUserNameMan Jul 24, 2024
865c66b
`rcore_desktop_glfw.c` : `SetMousePosition()` previous pos
SuperUserNameMan Jul 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 98 additions & 51 deletions src/platforms/rcore_desktop_glfw.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,19 @@ bool WindowShouldClose(void)
// Toggle fullscreen mode
void ToggleFullscreen(void)
{
if (IsWindowState(FLAG_BORDERLESS_WINDOWED_MODE))
{
// We can't go straighforward from one fullscreen mode to an other
// there needs to be at least one loop between them
// so we just toggle the currently active fullscreen mode and leave.
ToggleBorderlessWindowed();
Copy link
Contributor

@SoloByte SoloByte Jul 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a flag here like fullscreenChangePending = true; and in the main loop (after 1 frame) if this flag is true fullscreen is activated & fullscreenChangePending = false; (the same for borderless)

This is not important right now I just wanted to add it for later ;)

return;
}

if (!CORE.Window.fullscreen)
{
// Store previous window position (in case we exit fullscreen)
glfwGetWindowPos(platform.handle, &CORE.Window.position.x, &CORE.Window.position.y);
glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);

int monitorCount = 0;
int monitorIndex = GetCurrentMonitor();
Expand All @@ -156,21 +165,39 @@ void ToggleFullscreen(void)
// Use current monitor, so we correctly get the display the window is on
GLFWmonitor *monitor = (monitorIndex < monitorCount)? monitors[monitorIndex] : NULL;

// The size at which the content of the window shall be rendered
// taking into account the DPI scaling if FLAG_WINDOW_HIGHDPI is set :
int renderingWidth = GetRenderWidth();
int renderingHeight = GetRenderHeight();

if (monitor == NULL)
{
TRACELOG(LOG_WARNING, "GLFW: Failed to get monitor");
TRACELOG(LOG_WARNING, "GLFW: ToggleFullscreen() failed to get monitor");

CORE.Window.fullscreen = false;
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;

glfwSetWindowMonitor(platform.handle, NULL, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
// There is nothing more to do. Just leave the window where it is.
}
else
{
CORE.Window.fullscreen = true;
CORE.Window.flags |= FLAG_FULLSCREEN_MODE;

glfwSetWindowMonitor(platform.handle, monitor, 0, 0, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
// We need to save the "size at which the content of the window is rendered"
// because we might have FLAG_WINDOW_HIGHDPI enabled.

CORE.Window.previousScreen.width = renderingWidth;
CORE.Window.previousScreen.height = renderingHeight;

// GLFW will pick the best monitor resolution it can find for the size of rendering :
// TODO pick the resolution ourself and try to rescale and center with black borders
glfwSetWindowMonitor(platform.handle, monitor, 0, 0, renderingWidth, renderingHeight, GLFW_DONT_CARE);

// GLFW will call WindowSizeCallback too late after EndDrawing()
// Let's call it already so the user can access updated values without further delay :
const GLFWvidmode *mode = glfwGetVideoMode( monitor );
WindowSizeCallback(platform.handle, mode->width, mode->height);
}

}
Expand All @@ -179,9 +206,17 @@ void ToggleFullscreen(void)
CORE.Window.fullscreen = false;
CORE.Window.flags &= ~FLAG_FULLSCREEN_MODE;

glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.position.x, CORE.Window.position.y, CORE.Window.screen.width, CORE.Window.screen.height, GLFW_DONT_CARE);
// Ask GLFW to restore the window and the previous monitor resolution :
glfwSetWindowMonitor(platform.handle, NULL, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height, GLFW_DONT_CARE);

// GLFW will call WindowSizeCallback too late after EndDrawing()
// Let's call it already so the user can access updated values without further delay :
WindowSizeCallback(platform.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
}

// Refocus window
glfwFocusWindow(platform.handle);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also test what happens when focus is lost while being in fullscreen/borderless fullscreen mode in general (like tabbing out to another window) and what happens when focus is gained again.

Currently when I tab out of a fullscreen window (works fine) and then tab into it again it stays minimized on macOS.

There is callback for window focused in GLFW but I don't if it is used in raylib.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: WindowFocusCallback(GLFWwindow *window, int focused) is used in raylib but it only sets the focus flag


// Try to enable GPU V-Sync, so frames are limited to screen refresh rate (60Hz -> 60 FPS)
// NOTE: V-Sync can be enabled by graphic driver configuration
if (CORE.Window.flags & FLAG_VSYNC_HINT) glfwSwapInterval(1);
Expand All @@ -190,13 +225,13 @@ void ToggleFullscreen(void)
// 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;
// We can't go straighforward from one fullscreen mode to an other
// there needs to be at least one loop between them
// so we just toggle the currently active fullscreen mode and leave.
ToggleFullscreen();
wasOnFullscreen = true;
return;
}

const int monitor = GetCurrentMonitor();
Expand All @@ -211,27 +246,24 @@ void ToggleBorderlessWindowed(void)
{
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;

// Set undecorated and topmost modes and flags
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_FALSE);
CORE.Window.flags |= FLAG_WINDOW_UNDECORATED;
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_TRUE);
CORE.Window.flags |= FLAG_WINDOW_TOPMOST;

// Get monitor position and size
int monitorPosX = 0;
int monitorPosY = 0;
glfwGetMonitorPos(monitors[monitor], &monitorPosX, &monitorPosY);
const int monitorWidth = mode->width;
const int monitorHeight = mode->height;

// Set screen position and size
glfwSetWindowPos(platform.handle, monitorPosX, monitorPosY);
glfwSetWindowSize(platform.handle, monitorWidth, monitorHeight);
// Store screen position and size :
glfwGetWindowPos(platform.handle, &CORE.Window.previousPosition.x, &CORE.Window.previousPosition.y);

// We need to save the "render size" intead of the "screen size"
// because we might have FLAG_WINDOW_HIGHDPI enabled.

int renderWidth = GetRenderWidth();
int renderHeight = GetRenderHeight();

CORE.Window.previousScreen.width = renderWidth;
CORE.Window.previousScreen.height = renderHeight;

// Ask fullscreen window :
glfwSetWindowMonitor(platform.handle, monitors[monitor], 0, 0, mode->width, mode->height, mode->refreshRate);

// GLFW will call WindowSizeCallback too late after EndDrawing()
// Let's call it already so the user can access updated values without further delay :
WindowSizeCallback(platform.handle, mode->width, mode->height);

// Refocus window
glfwFocusWindow(platform.handle);
Expand All @@ -240,16 +272,17 @@ void ToggleBorderlessWindowed(void)
}
else
{
// Remove topmost and undecorated modes and flags
glfwSetWindowAttrib(platform.handle, GLFW_FLOATING, GLFW_FALSE);
CORE.Window.flags &= ~FLAG_WINDOW_TOPMOST;
glfwSetWindowAttrib(platform.handle, GLFW_DECORATED, GLFW_TRUE);
CORE.Window.flags &= ~FLAG_WINDOW_UNDECORATED;

// Return previous screen size and position
// NOTE: The order matters here, it must set size first, then set position, otherwise the screen will be positioned incorrectly
glfwSetWindowSize(platform.handle, CORE.Window.previousScreen.width, CORE.Window.previousScreen.height);
glfwSetWindowPos(platform.handle, CORE.Window.previousPosition.x, CORE.Window.previousPosition.y);
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);

// GLFW will call WindowSizeCallback too late after EndDrawing()
// Let's call it already so the user can access updated values without further delay :
WindowSizeCallback(platform.handle, prevWidth, prevHeight);

// Refocus window
glfwFocusWindow(platform.handle);
Expand Down Expand Up @@ -1302,12 +1335,15 @@ int InitPlatform(void)
// Resize window content area based on the monitor content scale.
// NOTE: This hint only has an effect on platforms where screen coordinates and pixels always map 1:1 such as Windows and X11.
// On platforms like macOS the resolution of the framebuffer is changed independently of the window size.
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Scale content area based on the monitor content scale where window is placed on
#if defined(__APPLE__)
glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
#endif
// Scale content area based on the monitor content scale where window is placed on
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE); // Only has effect on Windows and X11
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); // Only has effect on MacOS and Wayland
}
else
{
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
}
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);

// Mouse passthrough
if ((CORE.Window.flags & FLAG_WINDOW_MOUSE_PASSTHROUGH) > 0) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
Expand Down Expand Up @@ -1520,15 +1556,16 @@ int InitPlatform(void)

if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling.
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GLFW_TRUE);
#if !defined(__APPLE__)
// NOTE: On APPLE and Wayland platforms system should manage window/input scaling and also framebuffer scaling.
// Framebuffer scaling should be activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#if !defined(__APPLE__) && !defined(_GLFW_WAYLAND)
glfwGetFramebufferSize(platform.handle, &fbWidth, &fbHeight);

// Screen scaling matrix is required in case desired screen area is different from display area
CORE.Window.screenScale = MatrixScale((float)fbWidth/CORE.Window.screen.width, (float)fbHeight/CORE.Window.screen.height, 1.0f);

// Mouse input scaling for the new screen size
// TODO FIXME does Wayland requires mouse scaling too ?
SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
#endif
}
Expand Down Expand Up @@ -1666,13 +1703,23 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true;

if (IsWindowFullscreen()) return;

// Set current screen size

#if defined(__APPLE__) || defined(_GLFW_WAYLAND)
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
#else
if ((CORE.Window.flags & FLAG_WINDOW_HIGHDPI) > 0)
{
Vector2 windowScaleDPI = GetWindowScaleDPI();

CORE.Window.screen.width = (unsigned int)ceilf(width/windowScaleDPI.x);
CORE.Window.screen.height = (unsigned int)ceilf(height/windowScaleDPI.y);
}
else
{
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
}
#endif
// NOTE: Postprocessing texture is not scaled to new size
}

Expand Down
Loading