summaryrefslogtreecommitdiffstats
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/detect.py4
-rw-r--r--platform/android/doc_classes/EditorExportPlatformAndroid.xml2
-rw-r--r--platform/android/export/export_plugin.h1
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java6
-rw-r--r--platform/ios/detect.py2
-rw-r--r--platform/linuxbsd/wayland/display_server_wayland.cpp2
-rw-r--r--platform/macos/doc_classes/EditorExportPlatformMacOS.xml7
-rw-r--r--platform/macos/export/export_plugin.cpp16
-rw-r--r--platform/macos/export/export_plugin.h1
-rw-r--r--platform/web/js/libs/library_godot_fetch.js16
-rw-r--r--platform/windows/detect.py52
-rw-r--r--platform/windows/display_server_windows.cpp36
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--platform/windows/native_menu_windows.h1
14 files changed, 108 insertions, 40 deletions
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 50e4756ccf..937bdbaa07 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -167,9 +167,7 @@ def configure(env: "SConsEnvironment"):
env["AS"] = compiler_path + "/clang"
env.Append(
- CCFLAGS=(
- "-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden -fno-strict-aliasing".split()
- )
+ CCFLAGS=("-fpic -ffunction-sections -funwind-tables -fstack-protector-strong -fvisibility=hidden".split())
)
if get_min_sdk_version(env["ndk_platform"]) >= 24:
diff --git a/platform/android/doc_classes/EditorExportPlatformAndroid.xml b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
index 2fe5539e56..8c8bca2b7c 100644
--- a/platform/android/doc_classes/EditorExportPlatformAndroid.xml
+++ b/platform/android/doc_classes/EditorExportPlatformAndroid.xml
@@ -577,7 +577,7 @@
Allows an application to write to the user dictionary.
</member>
<member name="screen/immersive_mode" type="bool" setter="" getter="">
- If [code]true[/code], hides navigation and status bar.
+ If [code]true[/code], hides navigation and status bar. See [method DisplayServer.window_set_mode] to toggle it at runtime.
</member>
<member name="screen/support_large" type="bool" setter="" getter="">
Indicates whether the application supports larger screen form-factors.
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 7e1d626486..15e80f824d 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -35,6 +35,7 @@
#include "godot_plugin_config.h"
#endif // DISABLE_DEPRECATED
+#include "core/io/image.h"
#include "core/io/zip_io.h"
#include "core/os/os.h"
#include "editor/export/editor_export_platform.h"
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
index 4e8e82a70a..c44a6dd472 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -108,7 +108,7 @@ public final class PermissionsUtil {
} else {
PermissionInfo permissionInfo = getPermissionInfo(activity, permission);
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
- if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
+ if ((protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Requesting permission " + permission);
requestedPermissions.add(permission);
}
@@ -174,7 +174,7 @@ public final class PermissionsUtil {
try {
PermissionInfo permissionInfo = getPermissionInfo(activity, permissionName);
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
- if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, permissionName) != PackageManager.PERMISSION_GRANTED) {
+ if ((protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(activity, permissionName) != PackageManager.PERMISSION_GRANTED) {
activity.requestPermissions(new String[] { permissionName }, REQUEST_SINGLE_PERMISSION_REQ_CODE);
return false;
}
@@ -259,7 +259,7 @@ public final class PermissionsUtil {
} else {
PermissionInfo permissionInfo = getPermissionInfo(context, manifestPermission);
int protectionLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? permissionInfo.getProtection() : permissionInfo.protectionLevel;
- if (protectionLevel == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(context, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
+ if ((protectionLevel & PermissionInfo.PROTECTION_DANGEROUS) == PermissionInfo.PROTECTION_DANGEROUS && ContextCompat.checkSelfPermission(context, manifestPermission) == PackageManager.PERMISSION_GRANTED) {
grantedPermissions.add(manifestPermission);
}
}
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 53b6935986..0f7f938852 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -130,7 +130,7 @@ def configure(env: "SConsEnvironment"):
elif env["arch"] == "arm64":
env.Append(
CCFLAGS=(
- "-fobjc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing"
+ "-fobjc-arc -arch arm64 -fmessage-length=0"
" -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits"
" -fpascal-strings -fblocks -fvisibility=hidden -MMD -MT dependencies"
" -isysroot $IOS_SDK_PATH".split()
diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp
index 3fbbc263a0..71c721ca1d 100644
--- a/platform/linuxbsd/wayland/display_server_wayland.cpp
+++ b/platform/linuxbsd/wayland/display_server_wayland.cpp
@@ -1479,12 +1479,12 @@ DisplayServerWayland::DisplayServerWayland(const String &p_rendering_driver, Win
driver_found = true;
}
}
+#endif // GLES3_ENABLED
if (!driver_found) {
r_error = ERR_UNAVAILABLE;
ERR_FAIL_MSG("Video driver not found.");
}
-#endif // GLES3_ENABLED
cursor_set_shape(CURSOR_BUSY);
diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
index c261c252ba..dcaba9bbd2 100644
--- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
+++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
@@ -75,6 +75,13 @@
<member name="codesign/custom_options" type="PackedStringArray" setter="" getter="">
Array of the additional command line arguments passed to the code signing tool.
</member>
+ <member name="codesign/entitlements/additional" type="String" setter="" getter="">
+ Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/entitlements].entitlements[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
+ [codeblock lang=text]
+ &lt;key&gt;key_name&lt;/key&gt;
+ &lt;string&gt;value&lt;/string&gt;
+ [/codeblock]
+ </member>
<member name="codesign/entitlements/address_book" type="bool" setter="" getter="">
Enable to allow access to contacts in the user's address book, if it's enabled you should also provide usage message in the [member privacy/address_book_usage_description] option. See [url=https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_personal-information_addressbook]com.apple.security.personal-information.addressbook[/url].
</member>
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index c99e9cdd0c..7887e5d0ab 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -327,7 +327,7 @@ bool EditorExportPlatformMacOS::get_export_option_visibility(const EditorExportP
}
bool advanced_options_enabled = p_preset->are_advanced_options_enabled();
- if (p_option.begins_with("privacy")) {
+ if (p_option.begins_with("privacy") || p_option == "codesign/entitlements/additional") {
return advanced_options_enabled;
}
}
@@ -501,6 +501,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_movies", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/entitlements/app_sandbox/files_user_selected", PROPERTY_HINT_ENUM, "No,Read-only,Read-write"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::ARRAY, "codesign/entitlements/app_sandbox/helper_executables", PROPERTY_HINT_ARRAY_TYPE, itos(Variant::STRING) + "/" + itos(PROPERTY_HINT_GLOBAL_FILE) + ":"), Array()));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements/additional", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
#ifdef MACOS_ENABLED
@@ -2126,6 +2127,11 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
+ const String &additional_entitlements = p_preset->get("codesign/entitlements/additional");
+ if (!additional_entitlements.is_empty()) {
+ ent_f->store_line(additional_entitlements);
+ }
+
ent_f->store_line("</dict>");
ent_f->store_line("</plist>");
} else {
@@ -2288,6 +2294,14 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
}
}
+ if (FileAccess::exists(ent_path)) {
+ print_verbose("entitlements:\n" + FileAccess::get_file_as_string(ent_path));
+ }
+
+ if (FileAccess::exists(hlp_ent_path)) {
+ print_verbose("helper entitlements:\n" + FileAccess::get_file_as_string(hlp_ent_path));
+ }
+
// Clean up temporary entitlements files.
if (FileAccess::exists(hlp_ent_path)) {
DirAccess::remove_file_or_error(hlp_ent_path);
diff --git a/platform/macos/export/export_plugin.h b/platform/macos/export/export_plugin.h
index d88d347359..4ded2f3301 100644
--- a/platform/macos/export/export_plugin.h
+++ b/platform/macos/export/export_plugin.h
@@ -34,6 +34,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+#include "core/io/image.h"
#include "core/io/marshalls.h"
#include "core/io/resource_saver.h"
#include "core/os/os.h"
diff --git a/platform/web/js/libs/library_godot_fetch.js b/platform/web/js/libs/library_godot_fetch.js
index 00616bc1a5..eeb3978256 100644
--- a/platform/web/js/libs/library_godot_fetch.js
+++ b/platform/web/js/libs/library_godot_fetch.js
@@ -59,7 +59,12 @@ const GodotFetch = {
});
obj.status = response.status;
obj.response = response;
- obj.reader = response.body.getReader();
+ // `body` can be null per spec (for example, in cases where the request method is HEAD).
+ // As of the time of writing, Chromium (127.0.6533.72) does not follow the spec but Firefox (131.0.3) does.
+ // See godotengine/godot#76825 for more information.
+ // See Chromium revert (of the change to follow the spec):
+ // https://chromium.googlesource.com/chromium/src/+/135354b7bdb554cd03c913af7c90aceead03c4d4
+ obj.reader = response.body?.getReader();
obj.chunked = chunked;
},
@@ -121,6 +126,10 @@ const GodotFetch = {
}
obj.reading = true;
obj.reader.read().then(GodotFetch.onread.bind(null, id)).catch(GodotFetch.onerror.bind(null, id));
+ } else if (obj.reader == null && obj.response.body == null) {
+ // Emulate a stream closure to maintain the request lifecycle.
+ obj.reading = true;
+ GodotFetch.onread(id, { value: undefined, done: true });
}
},
},
@@ -159,7 +168,10 @@ const GodotFetch = {
if (!obj.response) {
return 0;
}
- if (obj.reader) {
+ // If the reader is nullish, but there is no body, and the request is not marked as done,
+ // the same status should be returned as though the request is currently being read
+ // so that the proper lifecycle closure can be handled in `read()`.
+ if (obj.reader || (obj.response.body == null && !obj.done)) {
return 1;
}
if (obj.done) {
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 14b99663d6..ddcd29adc9 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -483,9 +483,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
else:
print_warning("Missing environment variable: WindowsSdkDir")
- if int(env["target_win_version"], 16) < 0x0601:
- print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
- sys.exit(255)
+ validate_win_version(env)
env.AppendUnique(
CPPDEFINES=[
@@ -549,15 +547,7 @@ def configure_msvc(env: "SConsEnvironment", vcvars_msvc_config):
LIBS += ["vulkan"]
if env["d3d12"]:
- # Check whether we have d3d12 dependencies installed.
- if not os.path.exists(env["mesa_libs"]):
- print_error(
- "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
- "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
- "See the documentation for more information:\n\t"
- "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
- )
- sys.exit(255)
+ check_d3d12_installed(env)
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
LIBS += ["dxgi", "dxguid"]
@@ -662,7 +652,7 @@ def get_ar_version(env):
print_warning("Couldn't check version of `ar`.")
return ret
- match = re.search(r"GNU ar \(GNU Binutils\) (\d+)\.(\d+)(?:\.(\d+))?", output)
+ match = re.search(r"GNU ar(?: \(GNU Binutils\)| version) (\d+)\.(\d+)(?:\.(\d+))?", output)
if match:
ret["major"] = int(match[1])
ret["minor"] = int(match[2])
@@ -788,8 +778,9 @@ def configure_mingw(env: "SConsEnvironment"):
env["CXX"] = mingw_bin_prefix + "g++"
if try_cmd("as --version", env["mingw_prefix"], env["arch"]):
env["AS"] = mingw_bin_prefix + "as"
- if try_cmd("gcc-ar --version", env["mingw_prefix"], env["arch"]):
- env["AR"] = mingw_bin_prefix + "gcc-ar"
+ ar = "ar" if os.name == "nt" else "gcc-ar"
+ if try_cmd(f"{ar} --version", env["mingw_prefix"], env["arch"]):
+ env["AR"] = mingw_bin_prefix + ar
if try_cmd("gcc-ranlib --version", env["mingw_prefix"], env["arch"]):
env["RANLIB"] = mingw_bin_prefix + "gcc-ranlib"
@@ -819,9 +810,7 @@ def configure_mingw(env: "SConsEnvironment"):
## Compile flags
- if int(env["target_win_version"], 16) < 0x0601:
- print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
- sys.exit(255)
+ validate_win_version(env)
if not env["use_llvm"]:
env.Append(CCFLAGS=["-mwindows"])
@@ -899,15 +888,7 @@ def configure_mingw(env: "SConsEnvironment"):
env.Append(LIBS=["vulkan"])
if env["d3d12"]:
- # Check whether we have d3d12 dependencies installed.
- if not os.path.exists(env["mesa_libs"]):
- print_error(
- "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
- "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
- "See the documentation for more information:\n\t"
- "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
- )
- sys.exit(255)
+ check_d3d12_installed(env)
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
env.Append(LIBS=["dxgi", "dxguid"])
@@ -978,3 +959,20 @@ def configure(env: "SConsEnvironment"):
else: # MinGW
configure_mingw(env)
+
+
+def check_d3d12_installed(env):
+ if not os.path.exists(env["mesa_libs"]):
+ print_error(
+ "The Direct3D 12 rendering driver requires dependencies to be installed.\n"
+ "You can install them by running `python misc\\scripts\\install_d3d12_sdk_windows.py`.\n"
+ "See the documentation for more information:\n\t"
+ "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
+ )
+ sys.exit(255)
+
+
+def validate_win_version(env):
+ if int(env["target_win_version"], 16) < 0x0601:
+ print_error("`target_win_version` should be 0x0601 or higher (Windows 7).")
+ sys.exit(255)
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index ffa3840181..c427596829 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -67,6 +67,18 @@
#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
#endif
+#ifndef DWMWA_WINDOW_CORNER_PREFERENCE
+#define DWMWA_WINDOW_CORNER_PREFERENCE 33
+#endif
+
+#ifndef DWMWCP_DEFAULT
+#define DWMWCP_DEFAULT 0
+#endif
+
+#ifndef DWMWCP_DONOTROUND
+#define DWMWCP_DONOTROUND 1
+#endif
+
#define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1)
#if defined(__GNUC__)
@@ -1483,6 +1495,9 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_ALWAYS_ON_TOP_BIT && p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.always_on_top = true;
}
+ if (p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT) {
+ wd.sharp_corners = true;
+ }
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
wd.no_focus = true;
}
@@ -2297,6 +2312,12 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.always_on_top = p_enabled;
_update_window_style(p_window);
} break;
+ case WINDOW_FLAG_SHARP_CORNERS: {
+ wd.sharp_corners = p_enabled;
+ DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
+ ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
+ _update_window_style(p_window);
+ } break;
case WINDOW_FLAG_TRANSPARENT: {
if (p_enabled) {
// Enable per-pixel alpha.
@@ -3994,6 +4015,10 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
native_menu->_menu_activate(HMENU(lParam), (int)wParam);
} break;
case WM_CREATE: {
+ {
+ DWORD value = windows[window_id].sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
+ }
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
@@ -5645,6 +5670,12 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd_transient_parent->transient_children.insert(id);
}
+ wd.sharp_corners = p_flags & WINDOW_FLAG_SHARP_CORNERS_BIT;
+ {
+ DWORD value = wd.sharp_corners ? DWMWCP_DONOTROUND : DWMWCP_DEFAULT;
+ ::DwmSetWindowAttribute(wd.hWnd, DWMWA_WINDOW_CORNER_PREFERENCE, &value, sizeof(value));
+ }
+
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
@@ -6369,7 +6400,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution), false, INVALID_WINDOW_ID);
- ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
+ if (main_window == INVALID_WINDOW_ID) {
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Failed to create main window.");
+ }
joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 7d6a3e96a6..fc72e05b1d 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -38,6 +38,7 @@
#include "core/config/project_settings.h"
#include "core/input/input.h"
+#include "core/io/image.h"
#include "core/os/os.h"
#include "drivers/unix/ip_unix.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
@@ -473,6 +474,7 @@ class DisplayServerWindows : public DisplayServer {
bool exclusive = false;
bool context_created = false;
bool mpass = false;
+ bool sharp_corners = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
diff --git a/platform/windows/native_menu_windows.h b/platform/windows/native_menu_windows.h
index 235a4b332a..09e4640b40 100644
--- a/platform/windows/native_menu_windows.h
+++ b/platform/windows/native_menu_windows.h
@@ -31,6 +31,7 @@
#ifndef NATIVE_MENU_WINDOWS_H
#define NATIVE_MENU_WINDOWS_H
+#include "core/io/image.h"
#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "servers/display/native_menu.h"