diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index a05404826673..688e1b70cae9 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -1103,8 +1103,9 @@ Returns the scale factor of the specified screen by index. - [b]Note:[/b] On macOS returned value is [code]2.0[/code] for hiDPI (Retina) screen, and [code]1.0[/code] for all other cases. - [b]Note:[/b] This method is implemented only on macOS. + [b]Note:[/b] On macOS, the returned value is [code]2.0[/code] for hiDPI (Retina) screens, and [code]1.0[/code] for all other cases. + [b]Note:[/b] On Linux (Wayland), the returned value is accurate only when [param screen] is [constant SCREEN_OF_MAIN_WINDOW]. Due to API limitations, passing a direct index will return a rounded-up integer, if the screen has a fractional scale (e.g. [code]1.25[/code] would get rounded up to [code]2.0[/code]). + [b]Note:[/b] This method is implemented only on macOS and Linux (Wayland). diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index cec50ac30f0a..bd68fa5de58e 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1540,6 +1540,19 @@ String EditorSettings::get_editor_layouts_config() const { float EditorSettings::get_auto_display_scale() const { #ifdef LINUXBSD_ENABLED if (DisplayServer::get_singleton()->get_name() == "Wayland") { + float main_window_scale = DisplayServer::get_singleton()->screen_get_scale(DisplayServer::SCREEN_OF_MAIN_WINDOW); + + if (DisplayServer::get_singleton()->get_screen_count() == 1 || Math::fract(main_window_scale) != 0) { + // If we have a single screen or the screen of the window is fractional, all + // bets are off. At this point, let's just return the current's window scale, + // which is special-cased to the scale of `SCREEN_OF_MAIN_WINDOW`. + return main_window_scale; + } + + // If the above branch didn't fire, fractional scaling isn't going to work + // properly anyways (we're need the ability to change the UI scale at runtime). + // At this point it's more convenient to "supersample" like we do with other + // platforms, hoping that the user is only using integer-scaled screens. return DisplayServer::get_singleton()->screen_get_max_scale(); } #endif diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 1c3cae0435ef..f7995472d087 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -550,7 +550,15 @@ float DisplayServerWayland::screen_get_scale(int p_screen) const { MutexLock mutex_lock(wayland_thread.mutex); if (p_screen == SCREEN_OF_MAIN_WINDOW) { - p_screen = window_get_current_screen(); + // Wayland does not expose fractional scale factors at the screen-level, but + // some code relies on it. Since this special screen is the default and a lot + // of code relies on it, we'll return the window's scale, which is what we + // really care about. After all, we have very little use of the actual screen + // enumeration APIs and we're (for now) in single-window mode anyways. + struct wl_surface *wl_surface = wayland_thread.window_get_wl_surface(MAIN_WINDOW_ID); + WaylandThread::WindowState *ws = wayland_thread.wl_surface_get_window_state(wl_surface); + + return wayland_thread.window_state_get_scale_factor(ws); } return wayland_thread.screen_get_data(p_screen).scale;