-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Changes from 9 commits
949aa21
3f605e3
7ddb880
21bff48
a76adf9
545665d
b004531
1b800a1
32e9d88
312f9c2
dc4c60b
3c48b5c
a2d1e66
2d22514
a2ccd82
05b1720
b2c9c5e
0413845
310e4d7
9fb406a
c5f90a5
1a7657e
1902015
2ffca57
79316b2
02ae6e9
f3d8fc7
df62c80
02666be
0882f15
4ae3e55
9228338
d4ad622
108e3bd
eac2e6f
d4f3e1a
865c66b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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(); | ||
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(); | ||
|
@@ -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); | ||
} | ||
|
||
} | ||
|
@@ -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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI: |
||
|
||
// 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); | ||
|
@@ -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(); | ||
|
@@ -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); | ||
|
@@ -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); | ||
|
@@ -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); | ||
|
@@ -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 | ||
} | ||
|
@@ -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 | ||
} | ||
|
||
|
There was a problem hiding this comment.
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 ;)