REVIEWED: HighDPI support on macOS (when requested by app)

Tested on two monitors with different DPI configuration, for HigDPI enabled and not, including window resizing (with framebuffer resizing if required). Verified mouse coordinates follow the requested screen size.
This commit is contained in:
Ray
2025-12-22 22:48:08 +01:00
parent e4baf682ab
commit f27f2d097f

View File

@ -135,12 +135,12 @@ static void ErrorCallback(int error, const char *description);
// Window callbacks events // Window callbacks events
static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized static void WindowSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 WindowSize Callback, runs when window is resized
static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized static void FramebufferSizeCallback(GLFWwindow *window, int width, int height); // GLFW3 FramebufferSize Callback, runs when window is resized
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved static void WindowPosCallback(GLFWwindow *window, int x, int y); // GLFW3 WindowPos Callback, runs when window is moved
static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored static void WindowIconifyCallback(GLFWwindow *window, int iconified); // GLFW3 WindowIconify Callback, runs when window is minimized/restored
static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized static void WindowMaximizeCallback(GLFWwindow *window, int maximized); // GLFW3 Window Maximize Callback, runs when window is maximized
static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus static void WindowFocusCallback(GLFWwindow *window, int focused); // GLFW3 WindowFocus Callback, runs when window get/lose focus
static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window static void WindowDropCallback(GLFWwindow *window, int count, const char **paths); // GLFW3 Window Drop Callback, runs when drop files into window
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley); // GLFW3 Window Content Scale Callback, runs when window changes scale
// Input callbacks events // Input callbacks events
static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed static void KeyCallback(GLFWwindow *window, int key, int scancode, int action, int mods); // GLFW3 Keyboard Callback, runs on key pressed
@ -1024,8 +1024,8 @@ Vector2 GetWindowPosition(void)
// Get window scale DPI factor for current monitor // Get window scale DPI factor for current monitor
Vector2 GetWindowScaleDPI(void) Vector2 GetWindowScaleDPI(void)
{ {
Vector2 scale = { 0 }; Vector2 scale = { 1.0f, 1.0f };
glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y); if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) glfwGetWindowContentScale(platform.handle, &scale.x, &scale.y);
return scale; return scale;
} }
@ -1452,12 +1452,18 @@ int InitPlatform(void)
// NOTE: This hint only has an effect on platforms where screen coordinates and // NOTE: This hint only has an effect on platforms where screen coordinates and
// pixels always map 1:1 such as Windows and X11 // 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 // 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 glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
#if defined(__APPLE__) #if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
#endif #endif
} }
else glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); else
{
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE);
#if defined(__APPLE__)
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE);
#endif
}
// Mouse passthrough // Mouse passthrough
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE); if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MOUSE_PASSTHROUGH)) glfwWindowHint(GLFW_MOUSE_PASSTHROUGH, GLFW_TRUE);
@ -1527,9 +1533,7 @@ int InitPlatform(void)
GLFWmonitor *monitor = NULL; GLFWmonitor *monitor = NULL;
if (CORE.Window.fullscreen) if (CORE.Window.fullscreen)
{ {
// According to glfwCreateWindow(), if the user does not have a choice, fullscreen applications // NOTE: Fullscreen applications default to the primary monitor
// should default to the primary monitor
monitor = glfwGetPrimaryMonitor(); monitor = glfwGetPrimaryMonitor();
if (!monitor) if (!monitor)
{ {
@ -1538,7 +1542,7 @@ int InitPlatform(void)
} }
// Set dimensions from monitor // Set dimensions from monitor
GLFWvidmode *mode = glfwGetVideoMode(monitor); const GLFWvidmode *mode = glfwGetVideoMode(monitor);
// Default display resolution to that of the current mode // Default display resolution to that of the current mode
CORE.Window.display.width = mode->width; CORE.Window.display.width = mode->width;
@ -1635,7 +1639,7 @@ int InitPlatform(void)
if (monitorIndex < monitorCount) if (monitorIndex < monitorCount)
{ {
monitor = monitors[monitorIndex]; monitor = monitors[monitorIndex];
GLFWvidmode *mode = glfwGetVideoMode(monitor); const GLFWvidmode *mode = glfwGetVideoMode(monitor);
// Default display resolution to that of the current mode // Default display resolution to that of the current mode
CORE.Window.display.width = mode->width; CORE.Window.display.width = mode->width;
@ -1846,6 +1850,7 @@ static void WindowSizeCallback(GLFWwindow *window, int width, int height)
} }
// GLFW3: Framebuffer size change callback, runs when framebuffer is resized // GLFW3: Framebuffer size change callback, runs when framebuffer is resized
// WARNING: If FLAG_WINDOW_HIGHDPI is set, WindowContentScaleCallback() is called before this function
static void FramebufferSizeCallback(GLFWwindow *window, int width, int height) static void FramebufferSizeCallback(GLFWwindow *window, int width, int height)
{ {
//TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height); //TRACELOG(LOG_INFO, "GLFW3: Window framebuffer size callback called [%i,%i]", width, height);
@ -1863,32 +1868,26 @@ static void FramebufferSizeCallback(GLFWwindow *window, int width, int height)
CORE.Window.currentFbo.height = height; CORE.Window.currentFbo.height = height;
CORE.Window.resizedLastFrame = true; CORE.Window.resizedLastFrame = true;
if (IsWindowFullscreen()) return;
// Check if render size was actually scaled for high-dpi // Check if render size was actually scaled for high-dpi
if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI))
{ {
// Set screen size to logical pixel size, considering content scaling
Vector2 scaleDpi = GetWindowScaleDPI(); Vector2 scaleDpi = GetWindowScaleDPI();
width = (int)((float)width/scaleDpi.x); CORE.Window.screen.width = (int)((float)width/scaleDpi.x);
height = (int)((float)height/scaleDpi.y); CORE.Window.screen.height = (int)((float)height/scaleDpi.y);
}
else
{
// Set screen size to render size (physical pixel size)
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
} }
// Set current screen size
CORE.Window.screen.width = width;
CORE.Window.screen.height = height;
// WARNING: If using a render texture, it is not scaled to new size // WARNING: If using a render texture, it is not scaled to new size
} }
// GLFW3: Window position callback, runs when window position changes
static void WindowPosCallback(GLFWwindow *window, int x, int y)
{
// Set current window position
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
// GLFW3: Window content scale callback, runs on monitor content scale change detected // GLFW3: Window content scale callback, runs on monitor content scale change detected
// WARNING: If FLAG_WINDOW_HIGHDPI is not set, this function is not called
static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley) static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float scaley)
{ {
TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley); TRACELOG(LOG_INFO, "GLFW3: Window content scale changed, scale: [%.2f,%.2f]", scalex, scaley);
@ -1896,13 +1895,13 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s
float fbWidth = (float)CORE.Window.screen.width*scalex; float fbWidth = (float)CORE.Window.screen.width*scalex;
float fbHeight = (float)CORE.Window.screen.height*scaley; float fbHeight = (float)CORE.Window.screen.height*scaley;
#if !defined(__APPLE__)
// NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling // NOTE: On APPLE platforms system should manage window/input scaling and also framebuffer scaling
// Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE); // Framebuffer scaling is activated with: glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f); CORE.Window.screenScale = MatrixScale(scalex, scaley, 1.0f);
#if !defined(__APPLE__)
// Mouse input scaling for the new screen size // Mouse input scaling for the new screen size
SetMouseScale(1.0f/scalex, 1.0f/scaley); SetMouseScale((float)CORE.Window.screen.width/fbWidth, (float)CORE.Window.screen.height/fbHeight);
#endif #endif
CORE.Window.render.width = (int)fbWidth; CORE.Window.render.width = (int)fbWidth;
@ -1911,6 +1910,16 @@ static void WindowContentScaleCallback(GLFWwindow *window, float scalex, float s
CORE.Window.currentFbo.height = (int)fbHeight; CORE.Window.currentFbo.height = (int)fbHeight;
} }
// GLFW3: Window position callback, runs when window position changes
static void WindowPosCallback(GLFWwindow *window, int x, int y)
{
TRACELOG(LOG_INFO, "GLFW3: Window position changed");
// Set current window position
CORE.Window.position.x = x;
CORE.Window.position.y = y;
}
// GLFW3: Window iconify callback, runs when window is minimized/restored // GLFW3: Window iconify callback, runs when window is minimized/restored
static void WindowIconifyCallback(GLFWwindow *window, int iconified) static void WindowIconifyCallback(GLFWwindow *window, int iconified)
{ {