From 928982891e2ce0b6c7556aad08b5bb331bb64c5c Mon Sep 17 00:00:00 2001 From: Hugo Locurcio Date: Fri, 13 Dec 2024 17:16:14 +0100 Subject: [PATCH] Add `OS.get_version_alias()` to return a human-readable Windows/macOS version number Windows 11's major version number is actually 10.x.x, which can be confusing if you don't know about this quirk. `OS.get_version_alias()` avoids this by displaying the "branding" version number and the build number as a suffix, so that individual updates can still be distinguished from each other. On macOS, `OS.get_version_alias()` returns the version number prepended with the version name (e.g. Sequoia for macOS 15). On other operating systems, this returns the same value as `OS.get_version()`. --- core/core_bind.cpp | 5 ++ core/core_bind.h | 1 + core/os/os.h | 1 + doc/classes/OS.xml | 7 +++ editor/editor_node.cpp | 2 +- platform/macos/os_macos.h | 1 + platform/macos/os_macos.mm | 27 ++++++++++ platform/windows/display_server_windows.cpp | 1 - platform/windows/display_server_windows.h | 4 +- platform/windows/os_windows.cpp | 60 ++++++++++++++++++++- platform/windows/os_windows.h | 1 + 11 files changed, 105 insertions(+), 5 deletions(-) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 66bf5f41e14e..237d479989dd 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -424,6 +424,10 @@ String OS::get_version() const { return ::OS::get_singleton()->get_version(); } +String OS::get_version_alias() const { + return ::OS::get_singleton()->get_version_alias(); +} + Vector OS::get_video_adapter_driver_info() const { return ::OS::get_singleton()->get_video_adapter_driver_info(); } @@ -680,6 +684,7 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name); ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name); ClassDB::bind_method(D_METHOD("get_version"), &OS::get_version); + ClassDB::bind_method(D_METHOD("get_version_alias"), &OS::get_version_alias); ClassDB::bind_method(D_METHOD("get_cmdline_args"), &OS::get_cmdline_args); ClassDB::bind_method(D_METHOD("get_cmdline_user_args"), &OS::get_cmdline_user_args); diff --git a/core/core_bind.h b/core/core_bind.h index 3b0442bd65a0..102c973ebf83 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -208,6 +208,7 @@ class OS : public Object { String get_name() const; String get_distribution_name() const; String get_version() const; + String get_version_alias() const; Vector get_cmdline_args(); Vector get_cmdline_user_args(); diff --git a/core/os/os.h b/core/os/os.h index 4edfc68e2f7b..bff489adeac5 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -216,6 +216,7 @@ class OS { virtual String get_identifier() const; virtual String get_distribution_name() const = 0; virtual String get_version() const = 0; + virtual String get_version_alias() const { return get_version(); } virtual List get_cmdline_args() const { return _cmdline; } virtual List get_cmdline_user_args() const { return _user_args; } virtual List get_cmdline_platform_args() const { return List(); } diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 669c71778d2e..16a45bea435a 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -582,6 +582,13 @@ [b]Note:[/b] This method is not supported on the Web platform. It returns an empty string. + + + + Returns the branded version used in marketing, followed by the build number (on Windows) or the version number (on macOS). Examples include [code]11 (build 22000)[/code] and [code]Sequoia (15.0.0)[/code]. This value can then be appended to [method get_name] to get a full, human-readable operating system name and version combination for the operating system. Windows feature updates such as 24H2 are not contained in the resulting string, but Windows Server is recognized as such (e.g. [code]2025 (build 26100)[/code] for Windows Server 2025). + [b]Note:[/b] This method is only supported on Windows and macOS. On other operating systems, it returns the same value as [method get_version]. + + diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 5030589f5d87..f73eb011a6d4 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4977,7 +4977,7 @@ String EditorNode::_get_system_info() const { if (distribution_name.is_empty()) { distribution_name = "Other"; } - const String distribution_version = OS::get_singleton()->get_version(); + const String distribution_version = OS::get_singleton()->get_version_alias(); String godot_version = "Godot v" + String(VERSION_FULL_CONFIG); if (String(VERSION_BUILD) != "official") { diff --git a/platform/macos/os_macos.h b/platform/macos/os_macos.h index 939099d35027..194ba235e457 100644 --- a/platform/macos/os_macos.h +++ b/platform/macos/os_macos.h @@ -82,6 +82,7 @@ class OS_MacOS : public OS_Unix { virtual String get_name() const override; virtual String get_distribution_name() const override; virtual String get_version() const override; + virtual String get_version_alias() const override; virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm index 7357788f36db..d0ef4d1e3894 100644 --- a/platform/macos/os_macos.mm +++ b/platform/macos/os_macos.mm @@ -185,6 +185,33 @@ return vformat("%d.%d.%d", (int64_t)ver.majorVersion, (int64_t)ver.minorVersion, (int64_t)ver.patchVersion); } +String OS_MacOS::get_version_alias() const { + NSOperatingSystemVersion ver = [NSProcessInfo processInfo].operatingSystemVersion; + String macos_string; + if (ver.majorVersion == 15) { + macos_string += "Sequoia"; + } else if (ver.majorVersion == 14) { + macos_string += "Sonoma"; + } else if (ver.majorVersion == 13) { + macos_string += "Ventura"; + } else if (ver.majorVersion == 12) { + macos_string += "Monterey"; + } else if (ver.majorVersion == 11 || (ver.majorVersion == 10 && ver.minorVersion == 16)) { + // Big Sur was 10.16 during beta, but it became 11 for the stable version. + macos_string += "Big Sur"; + } else if (ver.majorVersion == 10 && ver.minorVersion == 15) { + macos_string += "Catalina"; + } else if (ver.majorVersion == 10 && ver.minorVersion == 14) { + macos_string += "Mojave"; + } else if (ver.majorVersion == 10 && ver.minorVersion == 13) { + macos_string += "High Sierra"; + } else { + macos_string += "Unknown"; + } + // macOS versions older than 10.13 cannot run Godot. + return vformat("%s (%s)", macos_string, get_version()); +} + void OS_MacOS::alert(const String &p_alert, const String &p_title) { NSAlert *window = [[NSAlert alloc] init]; NSString *ns_title = [NSString stringWithUTF8String:p_title.utf8().get_data()]; diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index a0d10549338d..2fa0ad8effd9 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -1480,7 +1480,6 @@ void DisplayServerWindows::screen_set_keep_on(bool p_enable) { if (p_enable) { const String reason = "Godot Engine running with display/window/energy_saving/keep_screen_on = true"; Char16String reason_utf16 = reason.utf16(); - REASON_CONTEXT context; context.Version = POWER_REQUEST_CONTEXT_VERSION; context.Flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 52a180984ba0..2ee6bd2e7302 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -167,7 +167,7 @@ typedef bool(WINAPI *ShouldAppsUseDarkModePtr)(); typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode); typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name); typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail); -typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOW *lpVersionInformation); +typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOEXW *lpVersionInformation); typedef bool(WINAPI *AllowDarkModeForAppPtr)(bool darkMode); typedef PreferredAppMode(WINAPI *SetPreferredAppModePtr)(PreferredAppMode appMode); typedef void(WINAPI *RefreshImmersiveColorPolicyStatePtr)(); @@ -419,7 +419,7 @@ class DisplayServerWindows : public DisplayServer { TIMER_ID_WINDOW_ACTIVATION = 2, }; - OSVERSIONINFOW os_ver; + OSVERSIONINFOEXW os_ver; enum { KEY_EVENT_BUFFER_SIZE = 512 diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 714f86dedf6b..93685cfcce94 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -582,7 +582,7 @@ String OS_Windows::get_distribution_name() const { String OS_Windows::get_version() const { RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); if (version_ptr != nullptr) { - RTL_OSVERSIONINFOW fow; + RTL_OSVERSIONINFOEXW fow; ZeroMemory(&fow, sizeof(fow)); fow.dwOSVersionInfoSize = sizeof(fow); if (version_ptr(&fow) == 0x00000000) { @@ -592,6 +592,64 @@ String OS_Windows::get_version() const { return ""; } +String OS_Windows::get_version_alias() const { + RtlGetVersionPtr version_ptr = (RtlGetVersionPtr)GetProcAddress(GetModuleHandle("ntdll.dll"), "RtlGetVersion"); + if (version_ptr != nullptr) { + RTL_OSVERSIONINFOEXW fow; + ZeroMemory(&fow, sizeof(fow)); + fow.dwOSVersionInfoSize = sizeof(fow); + if (version_ptr(&fow) == 0x00000000) { + String windows_string; + if (fow.wProductType != VER_NT_WORKSTATION && fow.dwMajorVersion == 10 && fow.dwBuildNumber >= 26100) { + windows_string = "Server 2025"; + } else if (fow.dwMajorVersion == 10 && fow.dwBuildNumber >= 20348) { + // Builds above 20348 correspond to Windows 11 / Windows Server 2022. + // Their major version numbers are still 10 though, not 11. + if (fow.wProductType != VER_NT_WORKSTATION) { + windows_string += "Server 2022"; + } else { + windows_string += "11"; + } + } else if (fow.dwMajorVersion == 10) { + if (fow.wProductType != VER_NT_WORKSTATION && fow.dwBuildNumber >= 17763) { + windows_string += "Server 2019"; + } else { + if (fow.wProductType != VER_NT_WORKSTATION) { + windows_string += "Server 2016"; + } else { + windows_string += "10"; + } + } + } else if (fow.dwMajorVersion == 6 && fow.dwMinorVersion == 3) { + if (fow.wProductType != VER_NT_WORKSTATION) { + windows_string = "Server 2012 R2"; + } else { + windows_string += "8.1"; + } + } else if (fow.dwMajorVersion == 6 && fow.dwMinorVersion == 2) { + if (fow.wProductType != VER_NT_WORKSTATION) { + windows_string += "Server 2012"; + } else { + windows_string += "8"; + } + } else if (fow.dwMajorVersion == 6 && fow.dwMinorVersion == 1) { + if (fow.wProductType != VER_NT_WORKSTATION) { + windows_string = "Server 2008 R2"; + } else { + windows_string += "7"; + } + } else { + windows_string += "Unknown"; + } + // Windows versions older than 7 cannot run Godot. + + return vformat("%s (build %d)", windows_string, (int64_t)fow.dwBuildNumber); + } + } + + return ""; +} + Vector OS_Windows::get_video_adapter_driver_info() const { if (RenderingServer::get_singleton() == nullptr) { return Vector(); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 43ab9d00f363..dc5d80933cde 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -178,6 +178,7 @@ class OS_Windows : public OS { virtual String get_name() const override; virtual String get_distribution_name() const override; virtual String get_version() const override; + virtual String get_version_alias() const override; virtual Vector get_video_adapter_driver_info() const override; virtual bool get_user_prefers_integrated_gpu() const override;