summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/README.md14
-rw-r--r--platform/android/android_input_handler.cpp2
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/android/dir_access_jandroid.cpp2
-rw-r--r--platform/android/export/export.cpp2
-rw-r--r--platform/android/export/export_plugin.cpp31
-rw-r--r--platform/android/export/export_plugin.h2
-rw-r--r--platform/android/export/gradle_export_util.cpp14
-rw-r--r--platform/android/export/gradle_export_util.h2
-rw-r--r--platform/android/java/app/AndroidManifest.xml5
-rw-r--r--platform/android/java/app/build.gradle3
-rw-r--r--platform/android/java/app/config.gradle14
-rw-r--r--platform/android/java/app/gradle.properties4
-rw-r--r--platform/android/java/gradle.properties4
-rw-r--r--platform/android/java/lib/build.gradle3
-rw-r--r--platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Helpers.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java21
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java31
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotHost.java6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotIO.java247
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java14
-rw-r--r--platform/android/java_godot_io_wrapper.cpp20
-rw-r--r--platform/android/java_godot_io_wrapper.h6
-rw-r--r--platform/android/logo.pngbin951 -> 968 bytes
-rw-r--r--platform/android/os_android.cpp18
-rw-r--r--platform/android/os_android.h5
-rw-r--r--platform/iphone/export/export_plugin.h2
-rw-r--r--platform/javascript/README.md15
-rw-r--r--platform/javascript/api/javascript_tools_editor_plugin.cpp32
-rw-r--r--platform/javascript/emscripten_helpers.py5
-rw-r--r--platform/javascript/export/export_plugin.h2
-rw-r--r--platform/javascript/js/libs/library_godot_os.js2
-rw-r--r--platform/javascript/os_javascript.cpp4
-rw-r--r--platform/linuxbsd/README.md11
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp10
-rw-r--r--platform/linuxbsd/export/export.cpp2
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp2
-rw-r--r--platform/linuxbsd/os_linuxbsd.h2
-rw-r--r--platform/osx/crash_handler_osx.mm10
-rw-r--r--platform/osx/display_server_osx.mm4
-rw-r--r--platform/osx/export/export_plugin.cpp4
-rw-r--r--platform/osx/export/export_plugin.h2
-rw-r--r--platform/osx/joypad_osx.cpp16
-rw-r--r--platform/osx/joypad_osx.h1
-rw-r--r--platform/osx/os_osx.h2
-rw-r--r--platform/osx/os_osx.mm2
-rw-r--r--platform/uwp/export/export_plugin.cpp2
-rw-r--r--platform/windows/crash_handler_windows.cpp10
-rw-r--r--platform/windows/detect.py2
-rw-r--r--platform/windows/display_server_windows.cpp327
-rw-r--r--platform/windows/os_windows.cpp2
-rw-r--r--platform/windows/os_windows.h2
52 files changed, 484 insertions, 465 deletions
diff --git a/platform/android/README.md b/platform/android/README.md
new file mode 100644
index 0000000000..343e588553
--- /dev/null
+++ b/platform/android/README.md
@@ -0,0 +1,14 @@
+# Android platform port
+
+This folder contains the Java and C++ (JNI) code for the Android platform port,
+using [Gradle](https://gradle.org/) as a build system.
+
+## Artwork license
+
+[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
+[Creative Commons Attribution 3.0 Unported](https://developer.android.com/distribute/marketing-tools/brand-guidelines#android_robot)
+per the Android logo usage guidelines:
+
+> The Android robot is reproduced or modified from work created and shared by
+> Google and used according to terms described in the Creative Commons 3.0
+> Attribution License.
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index b9004c4989..e03375e8d9 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -377,7 +377,7 @@ MouseButton AndroidInputHandler::_android_button_mask_to_godot_button_mask(int a
if (android_button_mask & AMOTION_EVENT_BUTTON_BACK) {
godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON1;
}
- if (android_button_mask & AMOTION_EVENT_BUTTON_SECONDARY) {
+ if (android_button_mask & AMOTION_EVENT_BUTTON_FORWARD) {
godot_button_mask |= MOUSE_BUTTON_MASK_XBUTTON2;
}
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 7a993e9ca6..61ccad9ac3 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -93,7 +93,7 @@ def configure(env):
install_ndk_if_needed(env)
# Workaround for MinGW. See:
- # http://www.scons.org/wiki/LongCmdLinesOnWin32
+ # https://www.scons.org/wiki/LongCmdLinesOnWin32
if os.name == "nt":
import subprocess
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 0bae090702..0eeee8215d 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -161,7 +161,7 @@ bool DirAccessJAndroid::dir_exists(String p_dir) {
if (current_dir == "")
sd = p_dir;
else {
- if (p_dir.is_rel_path())
+ if (p_dir.is_relative_path())
sd = current_dir.plus_file(p_dir);
else
sd = fix_path(p_dir);
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index fc86abb6f1..8df61831c2 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -48,6 +48,8 @@ void register_android_exporter() {
EDITOR_DEF("export/android/shutdown_adb_on_exit", true);
+ EDITOR_DEF("export/android/one_click_deploy_clear_previous_install", false);
+
Ref<EditorExportPlatformAndroid> exporter = Ref<EditorExportPlatformAndroid>(memnew(EditorExportPlatformAndroid));
EditorExport::get_singleton()->add_export_platform(exporter);
}
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 17ee173855..e5422a28af 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -717,6 +717,10 @@ Error EditorExportPlatformAndroid::copy_gradle_so(void *p_userdata, const Shared
return OK;
}
+bool EditorExportPlatformAndroid::_has_storage_permission(const Vector<String> &p_permissions) {
+ return p_permissions.find("android.permission.READ_EXTERNAL_STORAGE") != -1 || p_permissions.find("android.permission.WRITE_EXTERNAL_STORAGE") != -1;
+}
+
void EditorExportPlatformAndroid::_get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions) {
const char **aperms = android_perms;
while (*aperms) {
@@ -763,12 +767,17 @@ void EditorExportPlatformAndroid::_write_tmp_manifest(const Ref<EditorExportPres
Vector<String> perms;
_get_permissions(p_preset, p_give_internet, perms);
for (int i = 0; i < perms.size(); i++) {
- manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", perms.get(i));
+ String permission = perms.get(i);
+ if (permission == "android.permission.WRITE_EXTERNAL_STORAGE" || permission == "android.permission.READ_EXTERNAL_STORAGE") {
+ manifest_text += vformat(" <uses-permission android:name=\"%s\" android:maxSdkVersion=\"29\" />\n", permission);
+ } else {
+ manifest_text += vformat(" <uses-permission android:name=\"%s\" />\n", permission);
+ }
}
manifest_text += _get_xr_features_tag(p_preset);
manifest_text += _get_instrumentation_tag(p_preset);
- manifest_text += _get_application_tag(p_preset);
+ manifest_text += _get_application_tag(p_preset, _has_storage_permission(perms));
manifest_text += "</manifest>\n";
String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release"));
@@ -824,6 +833,7 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
Vector<String> perms;
// Write permissions into the perms variable.
_get_permissions(p_preset, p_give_internet, perms);
+ bool has_storage_permission = _has_storage_permission(perms);
while (ofs < (uint32_t)p_manifest.size()) {
uint32_t chunk = decode_uint32(&p_manifest[ofs]);
@@ -913,6 +923,10 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
}
}
+ if (tname == "application" && attrname == "requestLegacyExternalStorage") {
+ encode_uint32(has_storage_permission ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]);
+ }
+
if (tname == "application" && attrname == "allowBackup") {
encode_uint32(backup_allowed, &p_manifest.write[iofs + 16]);
}
@@ -963,6 +977,11 @@ void EditorExportPlatformAndroid::_fix_manifest(const Ref<EditorExportPreset> &p
Vector<int> feature_versions;
if (xr_mode_index == 1 /* XRMode.OVR */) {
+ // Set degrees of freedom
+ feature_names.push_back("android.hardware.vr.headtracking");
+ feature_required_list.push_back(true);
+ feature_versions.push_back(1);
+
// Check for hand tracking
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index > 0) {
@@ -1632,8 +1651,6 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false));
-
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname"));
@@ -1780,7 +1797,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
int rv;
String output;
- bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install");
+ bool remove_prev = EDITOR_GET("export/android/one_click_deploy_clear_previous_install");
String version_name = p_preset->get("version/name");
String package_name = p_preset->get("package/unique_name");
@@ -2597,7 +2614,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
String export_filename = p_path.get_file();
String export_path = p_path.get_base_dir();
- if (export_path.is_rel_path()) {
+ if (export_path.is_relative_path()) {
export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path);
}
export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path();
@@ -2925,7 +2942,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
void EditorExportPlatformAndroid::get_platform_features(List<String> *r_features) {
r_features->push_back("mobile");
- r_features->push_back("Android");
+ r_features->push_back("android");
}
void EditorExportPlatformAndroid::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index 909428c2fe..b061ee4e04 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -134,6 +134,8 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
static Error copy_gradle_so(void *p_userdata, const SharedObject &p_so);
+ bool _has_storage_permission(const Vector<String> &p_permissions);
+
void _get_permissions(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, Vector<String> &r_permissions);
void _write_tmp_manifest(const Ref<EditorExportPreset> &p_preset, bool p_give_internet, bool p_debug);
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index 76512226bf..6fbdf73cd0 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -197,6 +197,8 @@ String _get_xr_features_tag(const Ref<EditorExportPreset> &p_preset) {
String manifest_xr_features;
bool uses_xr = (int)(p_preset->get("xr_features/xr_mode")) == 1;
if (uses_xr) {
+ manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"android.hardware.vr.headtracking\" android:required=\"true\" android:version=\"1\" />\n";
+
int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required
if (hand_tracking_index == 1) {
manifest_xr_features += " <uses-feature tools:node=\"replace\" android:name=\"oculus.software.handtracking\" android:required=\"false\" />\n";
@@ -228,25 +230,29 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset) {
"tools:replace=\"android:screenOrientation\" "
"android:screenOrientation=\"%s\">\n",
orientation);
- if (!uses_xr) {
+ if (uses_xr) {
+ manifest_activity_text += " <meta-data tools:node=\"replace\" android:name=\"com.oculus.vr.focusaware\" android:value=\"true\" />\n";
+ } else {
manifest_activity_text += " <meta-data tools:node=\"remove\" android:name=\"com.oculus.vr.focusaware\" />\n";
}
manifest_activity_text += " </activity>\n";
return manifest_activity_text;
}
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset) {
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission) {
String manifest_application_text = vformat(
" <application android:label=\"@string/godot_project_name_string\"\n"
" android:allowBackup=\"%s\"\n"
" android:icon=\"@mipmap/icon\"\n"
" android:isGame=\"%s\"\n"
" android:hasFragileUserData=\"%s\"\n"
- " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData\"\n"
+ " android:requestLegacyExternalStorage=\"%s\"\n"
+ " tools:replace=\"android:allowBackup,android:isGame,android:hasFragileUserData,android:requestLegacyExternalStorage\"\n"
" tools:ignore=\"GoogleAppIndexingWarning\">\n\n",
bool_to_string(p_preset->get("user_data_backup/allow")),
bool_to_string(p_preset->get("package/classify_as_game")),
- bool_to_string(p_preset->get("package/retain_data_on_uninstall")));
+ bool_to_string(p_preset->get("package/retain_data_on_uninstall")),
+ bool_to_string(p_has_storage_permission));
manifest_application_text += _get_activity_tag(p_preset);
manifest_application_text += " </application>\n";
diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h
index 44e9a1727d..8a93c25d79 100644
--- a/platform/android/export/gradle_export_util.h
+++ b/platform/android/export/gradle_export_util.h
@@ -81,6 +81,6 @@ String _get_instrumentation_tag(const Ref<EditorExportPreset> &p_preset);
String _get_activity_tag(const Ref<EditorExportPreset> &p_preset);
-String _get_application_tag(const Ref<EditorExportPreset> &p_preset);
+String _get_application_tag(const Ref<EditorExportPreset> &p_preset, bool p_has_storage_permission);
#endif //GODOT_GRADLE_EXPORT_UTIL_H
diff --git a/platform/android/java/app/AndroidManifest.xml b/platform/android/java/app/AndroidManifest.xml
index 467a0dc3c0..d7bf6cef30 100644
--- a/platform/android/java/app/AndroidManifest.xml
+++ b/platform/android/java/app/AndroidManifest.xml
@@ -22,6 +22,7 @@
android:icon="@mipmap/icon"
android:isGame="true"
android:hasFragileUserData="false"
+ android:requestLegacyExternalStorage="false"
tools:ignore="GoogleAppIndexingWarning" >
<!-- Records the version of the Godot editor used for building -->
@@ -48,6 +49,10 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
+
+ <!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android
+ platforms. -->
+ <category android:name="com.oculus.intent.category.VR" />
</intent-filter>
</activity>
diff --git a/platform/android/java/app/build.gradle b/platform/android/java/app/build.gradle
index 18e07c3762..9640887399 100644
--- a/platform/android/java/app/build.gradle
+++ b/platform/android/java/app/build.gradle
@@ -34,9 +34,8 @@ allprojects {
}
dependencies {
- implementation libraries.supportCoreUtils
implementation libraries.kotlinStdLib
- implementation libraries.v4Support
+ implementation libraries.androidxFragment
if (rootProject.findProject(":lib")) {
implementation project(":lib")
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 81fc87b7ef..fcee54e493 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -1,12 +1,11 @@
ext.versions = [
- androidGradlePlugin: '4.2.1',
- compileSdk : 29,
- minSdk : 18,
- targetSdk : 29,
+ androidGradlePlugin: '4.2.2',
+ compileSdk : 30,
+ minSdk : 19,
+ targetSdk : 30,
buildTools : '30.0.3',
- supportCoreUtils : '1.0.0',
kotlinVersion : '1.5.10',
- v4Support : '1.0.0',
+ fragmentVersion : '1.3.6',
javaVersion : 1.8,
ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated.
@@ -14,10 +13,9 @@ ext.versions = [
ext.libraries = [
androidGradlePlugin: "com.android.tools.build:gradle:$versions.androidGradlePlugin",
- supportCoreUtils : "androidx.legacy:legacy-support-core-utils:$versions.supportCoreUtils",
kotlinGradlePlugin : "org.jetbrains.kotlin:kotlin-gradle-plugin:$versions.kotlinVersion",
kotlinStdLib : "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$versions.kotlinVersion",
- v4Support : "androidx.legacy:legacy-support-v4:$versions.v4Support"
+ androidxFragment : "androidx.fragment:fragment:$versions.fragmentVersion",
]
ext.getExportPackageName = { ->
diff --git a/platform/android/java/app/gradle.properties b/platform/android/java/app/gradle.properties
index 19587bd81f..0ad8e611ca 100644
--- a/platform/android/java/app/gradle.properties
+++ b/platform/android/java/app/gradle.properties
@@ -4,7 +4,7 @@
# where otherwise specified.
# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
+# https://www.gradle.org/docs/current/userguide/build_environment.html
android.enableJetifier=true
android.useAndroidX=true
@@ -15,7 +15,7 @@ org.gradle.jvmargs=-Xmx4536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# https://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
org.gradle.warning.mode=all
diff --git a/platform/android/java/gradle.properties b/platform/android/java/gradle.properties
index b51a19a005..5cd94e85d9 100644
--- a/platform/android/java/gradle.properties
+++ b/platform/android/java/gradle.properties
@@ -7,7 +7,7 @@
# any settings specified in this file.
# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
+# https://www.gradle.org/docs/current/userguide/build_environment.html
android.enableJetifier=true
android.useAndroidX=true
@@ -18,7 +18,7 @@ org.gradle.jvmargs=-Xmx4536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# https://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
org.gradle.warning.mode=all
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index 663ba73d40..fbed4ed078 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -2,9 +2,8 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
- implementation libraries.supportCoreUtils
implementation libraries.kotlinStdLib
- implementation libraries.v4Support
+ implementation libraries.androidxFragment
}
def pathToRootDir = "../../../../"
diff --git a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Helpers.java
index 2a72c9818d..9aa65fd786 100644
--- a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Helpers.java
+++ b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Helpers.java
@@ -54,7 +54,7 @@ public class Helpers {
/*
* Parse the Content-Disposition HTTP Header. The format of the header is defined here:
- * http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html This header provides a filename for
+ * https://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html This header provides a filename for
* content that is going to be downloaded to the file system. We only support the attachment
* type.
*/
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index ad7048cbf3..3600706c7c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -30,6 +30,7 @@
package org.godotengine.godot;
+import android.content.ComponentName;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -86,6 +87,26 @@ public abstract class FullScreenGodotApp extends FragmentActivity implements God
}
@Override
+ public final void onGodotRestartRequested(Godot instance) {
+ if (instance == godotFragment) {
+ // HACK:
+ //
+ // Currently it's very hard to properly deinitialize Godot on Android to restart the game
+ // from scratch. Therefore, we need to kill the whole app process and relaunch it.
+ //
+ // Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
+ // releasing and reloading native libs or resetting their state somehow and clearing statics).
+ //
+ // Using instrumentation is a way of making the whole app process restart, because Android
+ // will kill any process of the same package which was already running.
+ //
+ Bundle args = new Bundle();
+ args.putParcelable("intent", getIntent());
+ startInstrumentation(new ComponentName(this, GodotInstrumentation.class), null, args);
+ }
+ }
+
+ @Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if (godotFragment != null) {
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 76751a886c..70bc73b9ad 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -49,7 +49,6 @@ import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.ComponentName;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
@@ -68,15 +67,12 @@ import android.os.Environment;
import android.os.Messenger;
import android.os.VibrationEffect;
import android.os.Vibrator;
-import android.provider.Settings.Secure;
import android.view.Display;
-import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
-import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
@@ -299,7 +295,11 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
View pluginView = plugin.onMainCreate(activity);
if (pluginView != null) {
- containerLayout.addView(pluginView);
+ if (plugin.shouldBeOnTop()) {
+ containerLayout.addView(pluginView);
+ } else {
+ containerLayout.addView(pluginView, 0);
+ }
}
}
}
@@ -321,7 +321,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
@SuppressLint("MissingPermission")
@Keep
private void vibrate(int durationMs) {
- if (requestPermission("VIBRATE")) {
+ if (durationMs > 0 && requestPermission("VIBRATE")) {
Vibrator v = (Vibrator)getContext().getSystemService(Context.VIBRATOR_SERVICE);
if (v != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@@ -335,22 +335,8 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
}
public void restart() {
- // HACK:
- //
- // Currently it's very hard to properly deinitialize Godot on Android to restart the game
- // from scratch. Therefore, we need to kill the whole app process and relaunch it.
- //
- // Restarting only the activity, wouldn't be enough unless it did proper cleanup (including
- // releasing and reloading native libs or resetting their state somehow and clearing statics).
- //
- // Using instrumentation is a way of making the whole app process restart, because Android
- // will kill any process of the same package which was already running.
- //
- final Activity activity = getActivity();
- if (activity != null) {
- Bundle args = new Bundle();
- args.putParcelable("intent", mCurrentIntent);
- activity.startInstrumentation(new ComponentName(activity, GodotInstrumentation.class), null, args);
+ if (godotHost != null) {
+ godotHost.onGodotRestartRequested(this);
}
}
@@ -471,7 +457,6 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
final Activity activity = getActivity();
io = new GodotIO(activity);
- io.unique_id = Secure.getString(activity.getContentResolver(), Secure.ANDROID_ID);
GodotLib.io = io;
netUtils = new GodotNetUtils(activity);
mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
index 58e982c569..7b22895994 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotHost.java
@@ -58,4 +58,10 @@ public interface GodotHost {
* Invoked on the UI thread as the last step of the Godot instance clean up phase.
*/
default void onGodotForceQuit(Godot instance) {}
+
+ /**
+ * Invoked on the GL thread when the Godot instance wants to be restarted. It's up to the host
+ * to perform the appropriate action(s).
+ */
+ default void onGodotRestartRequested(Godot instance) {}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
index 66882e8e72..d85d88ec6c 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java
@@ -30,15 +30,19 @@
package org.godotengine.godot;
-import org.godotengine.godot.input.*;
+import org.godotengine.godot.input.GodotEditText;
import android.app.Activity;
-import android.content.*;
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.AssetManager;
import android.graphics.Point;
import android.net.Uri;
-import android.os.*;
+import android.os.Build;
+import android.os.Environment;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
@@ -47,14 +51,16 @@ import android.view.DisplayCutout;
import android.view.WindowInsets;
import java.io.IOException;
-import java.io.InputStream;
import java.util.Locale;
// Wrapper for native library
public class GodotIO {
- AssetManager am;
- final Activity activity;
+ private static final String TAG = GodotIO.class.getSimpleName();
+
+ private final AssetManager am;
+ private final Activity activity;
+ private final String uniqueId;
GodotEditText edit;
final int SCREEN_LANDSCAPE = 0;
@@ -66,167 +72,6 @@ public class GodotIO {
final int SCREEN_SENSOR = 6;
/////////////////////////
- /// FILES
- /////////////////////////
-
- public int last_file_id = 1;
-
- static class AssetData {
- public boolean eof = false;
- public String path;
- public InputStream is;
- public int len;
- public int pos;
- }
-
- SparseArray<AssetData> streams;
-
- public int file_open(String path, boolean write) {
- //System.out.printf("file_open: Attempt to Open %s\n",path);
-
- //Log.v("MyApp", "TRYING TO OPEN FILE: " + path);
- if (write)
- return -1;
-
- AssetData ad = new AssetData();
-
- try {
- ad.is = am.open(path);
-
- } catch (Exception e) {
- //System.out.printf("Exception on file_open: %s\n",path);
- return -1;
- }
-
- try {
- ad.len = ad.is.available();
- } catch (Exception e) {
- System.out.printf("Exception availabling on file_open: %s\n", path);
- return -1;
- }
-
- ad.path = path;
- ad.pos = 0;
- ++last_file_id;
- streams.put(last_file_id, ad);
-
- return last_file_id;
- }
- public int file_get_size(int id) {
- if (streams.get(id) == null) {
- System.out.printf("file_get_size: Invalid file id: %d\n", id);
- return -1;
- }
-
- return streams.get(id).len;
- }
- public void file_seek(int id, int bytes) {
- if (streams.get(id) == null) {
- System.out.printf("file_get_size: Invalid file id: %d\n", id);
- return;
- }
- //seek sucks
- AssetData ad = streams.get(id);
- if (bytes > ad.len)
- bytes = ad.len;
- if (bytes < 0)
- bytes = 0;
-
- try {
- if (bytes > (int)ad.pos) {
- int todo = bytes - (int)ad.pos;
- while (todo > 0) {
- todo -= ad.is.skip(todo);
- }
- ad.pos = bytes;
- } else if (bytes < (int)ad.pos) {
- ad.is = am.open(ad.path);
-
- ad.pos = bytes;
- int todo = bytes;
- while (todo > 0) {
- todo -= ad.is.skip(todo);
- }
- }
-
- ad.eof = false;
- } catch (IOException e) {
- System.out.printf("Exception on file_seek: %s\n", e);
- return;
- }
- }
-
- public int file_tell(int id) {
- if (streams.get(id) == null) {
- System.out.printf("file_read: Can't tell eof for invalid file id: %d\n", id);
- return 0;
- }
-
- AssetData ad = streams.get(id);
- return ad.pos;
- }
- public boolean file_eof(int id) {
- if (streams.get(id) == null) {
- System.out.printf("file_read: Can't check eof for invalid file id: %d\n", id);
- return false;
- }
-
- AssetData ad = streams.get(id);
- return ad.eof;
- }
-
- public byte[] file_read(int id, int bytes) {
- if (streams.get(id) == null) {
- System.out.printf("file_read: Can't read invalid file id: %d\n", id);
- return new byte[0];
- }
-
- AssetData ad = streams.get(id);
-
- if (ad.pos + bytes > ad.len) {
- bytes = ad.len - ad.pos;
- ad.eof = true;
- }
-
- if (bytes == 0) {
- return new byte[0];
- }
-
- byte[] buf1 = new byte[bytes];
- int r = 0;
- try {
- r = ad.is.read(buf1);
- } catch (IOException e) {
- System.out.printf("Exception on file_read: %s\n", e);
- return new byte[bytes];
- }
-
- if (r == 0) {
- return new byte[0];
- }
-
- ad.pos += r;
-
- if (r < bytes) {
- byte[] buf2 = new byte[r];
- for (int i = 0; i < r; i++)
- buf2[i] = buf1[i];
- return buf2;
- } else {
- return buf1;
- }
- }
-
- public void file_close(int id) {
- if (streams.get(id) == null) {
- System.out.printf("file_close: Can't close invalid file id: %d\n", id);
- return;
- }
-
- streams.remove(id);
- }
-
- /////////////////////////
/// DIRECTORIES
/////////////////////////
@@ -236,9 +81,9 @@ public class GodotIO {
public String path;
}
- public int last_dir_id = 1;
+ private int last_dir_id = 1;
- SparseArray<AssetDir> dirs;
+ private final SparseArray<AssetDir> dirs;
public int dir_open(String path) {
AssetDir ad = new AssetDir();
@@ -257,7 +102,6 @@ public class GodotIO {
return -1;
}
- //System.out.printf("Opened dir: %s\n",path);
++last_dir_id;
dirs.put(last_dir_id, ad);
@@ -320,9 +164,14 @@ public class GodotIO {
GodotIO(Activity p_activity) {
am = p_activity.getAssets();
activity = p_activity;
- //streams = new HashMap<Integer, AssetData>();
- streams = new SparseArray<>();
dirs = new SparseArray<>();
+ String androidId = Settings.Secure.getString(activity.getContentResolver(),
+ Settings.Secure.ANDROID_ID);
+ if (androidId == null) {
+ androidId = "";
+ }
+
+ uniqueId = androidId;
}
/////////////////////////
@@ -331,7 +180,6 @@ public class GodotIO {
public int openURI(String p_uri) {
try {
- Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
String path = p_uri;
String type = "";
if (path.startsWith("/")) {
@@ -357,12 +205,12 @@ public class GodotIO {
}
}
- public String getDataDir() {
- return activity.getFilesDir().getAbsolutePath();
+ public String getCacheDir() {
+ return activity.getCacheDir().getAbsolutePath();
}
- public String getExternalDataDir() {
- return activity.getExternalFilesDir(null).getAbsolutePath();
+ public String getDataDir() {
+ return activity.getFilesDir().getAbsolutePath();
}
public String getLocale() {
@@ -456,51 +304,58 @@ public class GodotIO {
public static final int SYSTEM_DIR_PICTURES = 6;
public static final int SYSTEM_DIR_RINGTONES = 7;
- public String getSystemDir(int idx) {
- String what = "";
+ public String getSystemDir(int idx, boolean shared_storage) {
+ String what;
switch (idx) {
- case SYSTEM_DIR_DESKTOP: {
- //what=Environment.DIRECTORY_DOCUMENTS;
- what = Environment.DIRECTORY_DOWNLOADS;
+ case SYSTEM_DIR_DESKTOP:
+ default: {
+ what = null; // This leads to the app specific external root directory.
} break;
+
case SYSTEM_DIR_DCIM: {
what = Environment.DIRECTORY_DCIM;
-
} break;
+
case SYSTEM_DIR_DOCUMENTS: {
- what = Environment.DIRECTORY_DOWNLOADS;
- //what=Environment.DIRECTORY_DOCUMENTS;
+ what = Environment.DIRECTORY_DOCUMENTS;
} break;
+
case SYSTEM_DIR_DOWNLOADS: {
what = Environment.DIRECTORY_DOWNLOADS;
-
} break;
+
case SYSTEM_DIR_MOVIES: {
what = Environment.DIRECTORY_MOVIES;
-
} break;
+
case SYSTEM_DIR_MUSIC: {
what = Environment.DIRECTORY_MUSIC;
} break;
+
case SYSTEM_DIR_PICTURES: {
what = Environment.DIRECTORY_PICTURES;
} break;
+
case SYSTEM_DIR_RINGTONES: {
what = Environment.DIRECTORY_RINGTONES;
-
} break;
}
- if (what.equals(""))
- return "";
- return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath();
+ if (shared_storage) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ Log.w(TAG, "Shared storage access is limited on Android 10 and higher.");
+ }
+ if (TextUtils.isEmpty(what)) {
+ return Environment.getExternalStorageDirectory().getAbsolutePath();
+ } else {
+ return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath();
+ }
+ } else {
+ return activity.getExternalFilesDir(what).getAbsolutePath();
+ }
}
- protected static final String PREFS_FILE = "device_id.xml";
- protected static final String PREFS_DEVICE_ID = "device_id";
-
- public static String unique_id = "";
public String getUniqueID() {
- return unique_id;
+ return uniqueId;
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index 2dc8359615..4536c21ed3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -191,6 +191,9 @@ public abstract class GodotPlugin {
* The plugin can return a non-null {@link View} layout in order to add it to the Godot view
* hierarchy.
*
+ * Use shouldBeOnTop() to set whether the plugin's {@link View} should be added on top or behind
+ * the main Godot view.
+ *
* @see Activity#onCreate(Bundle)
* @return the plugin's view to be included; null if no views should be included.
*/
@@ -311,6 +314,17 @@ public abstract class GodotPlugin {
}
/**
+ * Returns whether the plugin's {@link View} returned in onMainCreate() should be placed on
+ * top of the main Godot view.
+ *
+ * Returning false causes the plugin's {@link View} to be placed behind, which can be useful
+ * when used with transparency in order to let the Godot view handle inputs.
+ */
+ public boolean shouldBeOnTop() {
+ return true;
+ }
+
+ /**
* Runs the specified action on the UI thread. If the current thread is the UI
* thread, then the action is executed immediately. If the current thread is
* not the UI thread, the action is posted to the event queue of the UI thread.
diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp
index 5e99135498..5cd2c382d2 100644
--- a/platform/android/java_godot_io_wrapper.cpp
+++ b/platform/android/java_godot_io_wrapper.cpp
@@ -48,8 +48,8 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
}
_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
+ _get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;");
_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;");
- _get_external_data_dir = p_env->GetMethodID(cls, "getExternalDataDir", "()Ljava/lang/String;");
_get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
@@ -59,7 +59,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
_hide_keyboard = p_env->GetMethodID(cls, "hideKeyboard", "()V");
_set_screen_orientation = p_env->GetMethodID(cls, "setScreenOrientation", "(I)V");
_get_screen_orientation = p_env->GetMethodID(cls, "getScreenOrientation", "()I");
- _get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(I)Ljava/lang/String;");
+ _get_system_dir = p_env->GetMethodID(cls, "getSystemDir", "(IZ)Ljava/lang/String;");
}
}
@@ -82,22 +82,22 @@ Error GodotIOJavaWrapper::open_uri(const String &p_uri) {
}
}
-String GodotIOJavaWrapper::get_user_data_dir() {
- if (_get_data_dir) {
+String GodotIOJavaWrapper::get_cache_dir() {
+ if (_get_cache_dir) {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND_V(env == nullptr, String());
- jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_cache_dir);
return jstring_to_string(s, env);
} else {
return String();
}
}
-String GodotIOJavaWrapper::get_external_data_dir() {
- if (_get_external_data_dir) {
+String GodotIOJavaWrapper::get_user_data_dir() {
+ if (_get_data_dir) {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND_V(env == nullptr, String());
- jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_external_data_dir);
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_data_dir);
return jstring_to_string(s, env);
} else {
return String();
@@ -200,11 +200,11 @@ int GodotIOJavaWrapper::get_screen_orientation() {
}
}
-String GodotIOJavaWrapper::get_system_dir(int p_dir) {
+String GodotIOJavaWrapper::get_system_dir(int p_dir, bool p_shared_storage) {
if (_get_system_dir) {
JNIEnv *env = get_jni_env();
ERR_FAIL_COND_V(env == nullptr, String("."));
- jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir);
+ jstring s = (jstring)env->CallObjectMethod(godot_io_instance, _get_system_dir, p_dir, p_shared_storage);
return jstring_to_string(s, env);
} else {
return String(".");
diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h
index e4c0a4b2c7..8f6d7f813f 100644
--- a/platform/android/java_godot_io_wrapper.h
+++ b/platform/android/java_godot_io_wrapper.h
@@ -46,8 +46,8 @@ private:
jclass cls;
jmethodID _open_URI = 0;
+ jmethodID _get_cache_dir = 0;
jmethodID _get_data_dir = 0;
- jmethodID _get_external_data_dir = 0;
jmethodID _get_locale = 0;
jmethodID _get_model = 0;
jmethodID _get_screen_DPI = 0;
@@ -66,8 +66,8 @@ public:
jobject get_instance();
Error open_uri(const String &p_uri);
+ String get_cache_dir();
String get_user_data_dir();
- String get_external_data_dir();
String get_locale();
String get_model();
int get_screen_dpi();
@@ -80,7 +80,7 @@ public:
void set_vk_height(int p_height);
void set_screen_orientation(int p_orient);
int get_screen_orientation();
- String get_system_dir(int p_dir);
+ String get_system_dir(int p_dir, bool p_shared_storage);
};
#endif /* !JAVA_GODOT_IO_WRAPPER_H */
diff --git a/platform/android/logo.png b/platform/android/logo.png
index f44d360a25..9c8be93646 100644
--- a/platform/android/logo.png
+++ b/platform/android/logo.png
Binary files differ
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index c2e12442b3..21fb31d991 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -213,6 +213,10 @@ String OS_Android::get_model_name() const {
return OS_Unix::get_model_name();
}
+String OS_Android::get_data_path() const {
+ return get_user_data_dir();
+}
+
String OS_Android::get_user_data_dir() const {
if (data_dir_cache != String())
return data_dir_cache;
@@ -225,11 +229,11 @@ String OS_Android::get_user_data_dir() const {
return ".";
}
-String OS_Android::get_external_data_dir() const {
- String data_dir = godot_io_java->get_external_data_dir();
- if (data_dir != "") {
- data_dir = _remove_symlink(data_dir);
- return data_dir;
+String OS_Android::get_cache_path() const {
+ String cache_dir = godot_io_java->get_cache_dir();
+ if (cache_dir != "") {
+ cache_dir = _remove_symlink(cache_dir);
+ return cache_dir;
}
return ".";
}
@@ -242,8 +246,8 @@ String OS_Android::get_unique_id() const {
return OS::get_unique_id();
}
-String OS_Android::get_system_dir(SystemDir p_dir) const {
- return godot_io_java->get_system_dir(p_dir);
+String OS_Android::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
+ return godot_io_java->get_system_dir(p_dir, p_shared_storage);
}
void OS_Android::set_display_size(const Size2i &p_size) {
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index a5b995a775..c938297821 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -110,14 +110,15 @@ public:
virtual Error shell_open(String p_uri) override;
virtual String get_user_data_dir() const override;
- virtual String get_external_data_dir() const override;
+ virtual String get_data_path() const override;
+ virtual String get_cache_path() const override;
virtual String get_resource_dir() const override;
virtual String get_locale() const override;
virtual String get_model_name() const override;
virtual String get_unique_id() const override;
- virtual String get_system_dir(SystemDir p_dir) const override;
+ virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
void vibrate_handheld(int p_duration_ms) override;
diff --git a/platform/iphone/export/export_plugin.h b/platform/iphone/export/export_plugin.h
index 8d3af6e057..359f855d86 100644
--- a/platform/iphone/export/export_plugin.h
+++ b/platform/iphone/export/export_plugin.h
@@ -204,7 +204,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("mobile");
- r_features->push_back("iOS");
+ r_features->push_back("ios");
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/javascript/README.md b/platform/javascript/README.md
new file mode 100644
index 0000000000..f181bea9e0
--- /dev/null
+++ b/platform/javascript/README.md
@@ -0,0 +1,15 @@
+# HTML5 platform port
+
+This folder contains the C++ and JavaScript code for the HTML5/WebAssembly platform port,
+compiled using [Emscripten](https://emscripten.org/).
+
+It also contains a ESLint linting setup (see [`package.json`](package.json)).
+
+See also [`misc/dist/html`](/misc/dist/html) folder for files used by this platform
+such as the HTML5 shell.
+
+## Artwork license
+
+[`logo.png`](logo.png) and [`run_icon.png`](run_icon.png) are licensed under
+[Creative Commons Attribution 3.0 Unported](https://www.w3.org/html/logo/faq.html#how-licenced)
+per the HTML5 logo usage guidelines.
diff --git a/platform/javascript/api/javascript_tools_editor_plugin.cpp b/platform/javascript/api/javascript_tools_editor_plugin.cpp
index 54f541f607..c50195639c 100644
--- a/platform/javascript/api/javascript_tools_editor_plugin.cpp
+++ b/platform/javascript/api/javascript_tools_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "core/config/project_settings.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+#include "core/os/time.h"
#include "editor/editor_node.h"
#include <emscripten/emscripten.h>
@@ -58,23 +59,40 @@ JavaScriptToolsEditorPlugin::JavaScriptToolsEditorPlugin(EditorNode *p_editor) {
void JavaScriptToolsEditorPlugin::_download_zip(Variant p_v) {
if (!Engine::get_singleton() || !Engine::get_singleton()->is_editor_hint()) {
- WARN_PRINT("Project download is only available in Editor mode");
+ ERR_PRINT("Downloading the project as a ZIP archive is only available in Editor mode.");
return;
}
String resource_path = ProjectSettings::get_singleton()->get_resource_path();
FileAccess *src_f;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
- zipFile zip = zipOpen2("/tmp/project.zip", APPEND_STATUS_CREATE, nullptr, &io);
- String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
+
+ // Name the downloded ZIP file to contain the project name and download date for easier organization.
+ // Replace characters not allowed (or risky) in Windows file names with safe characters.
+ // In the project name, all invalid characters become an empty string so that a name
+ // like "Platformer 2: Godette's Revenge" becomes "platformer_2-_godette-s_revenge".
+ const String project_name_safe =
+ GLOBAL_GET("application/config/name").to_lower().replace(" ", "_");
+ const String datetime_safe =
+ Time::get_singleton()->get_datetime_string_from_system(false, true).replace(" ", "_");
+ const String output_name = OS::get_singleton()->get_safe_dir_name(vformat("%s_%s.zip"));
+ const String output_path = String("/tmp").plus_file(output_name);
+
+ zipFile zip = zipOpen2(output_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io);
+ const String base_path = resource_path.substr(0, resource_path.rfind("/")) + "/";
_zip_recursive(resource_path, base_path, zip);
zipClose(zip, nullptr);
- FileAccess *f = FileAccess::open("/tmp/project.zip", FileAccess::READ);
- ERR_FAIL_COND_MSG(!f, "Unable to create zip file");
+ FileAccess *f = FileAccess::open(output_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(!f, "Unable to create ZIP file.");
Vector<uint8_t> buf;
buf.resize(f->get_length());
f->get_buffer(buf.ptrw(), buf.size());
- godot_js_os_download_buffer(buf.ptr(), buf.size(), "project.zip", "application/zip");
+ godot_js_os_download_buffer(buf.ptr(), buf.size(), output_name.utf8().get_data(), "application/zip");
+
+ f->close();
+ memdelete(f);
+ // Remove the temporary file since it was sent to the user's native filesystem as a download.
+ DirAccess::remove_file_or_error(output_path);
}
void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, zipFile p_zip) {
@@ -108,7 +126,7 @@ void JavaScriptToolsEditorPlugin::_zip_file(String p_path, String p_base_path, z
void JavaScriptToolsEditorPlugin::_zip_recursive(String p_path, String p_base_path, zipFile p_zip) {
DirAccess *dir = DirAccess::open(p_path);
if (!dir) {
- WARN_PRINT("Unable to open dir for zipping: " + p_path);
+ WARN_PRINT("Unable to open directory for zipping: " + p_path);
return;
}
dir->list_dir_begin();
diff --git a/platform/javascript/emscripten_helpers.py b/platform/javascript/emscripten_helpers.py
index ab98838e20..4dad2d5204 100644
--- a/platform/javascript/emscripten_helpers.py
+++ b/platform/javascript/emscripten_helpers.py
@@ -24,7 +24,10 @@ def get_build_version():
v = "%d.%d" % (version.major, version.minor)
if version.patch > 0:
v += ".%d" % version.patch
- v += ".%s.%s" % (version.status, name)
+ status = version.status
+ if os.getenv("GODOT_VERSION_STATUS") != None:
+ status = str(os.getenv("GODOT_VERSION_STATUS"))
+ v += ".%s.%s" % (status, name)
return v
diff --git a/platform/javascript/export/export_plugin.h b/platform/javascript/export/export_plugin.h
index 736edfe3a8..bdd1235259 100644
--- a/platform/javascript/export/export_plugin.h
+++ b/platform/javascript/export/export_plugin.h
@@ -134,7 +134,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("web");
- r_features->push_back(get_os_name());
+ r_features->push_back(get_os_name().to_lower());
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 5aa750757c..99e7ee8b5f 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -106,7 +106,7 @@ autoAddDeps(GodotConfig, '$GodotConfig');
mergeInto(LibraryManager.library, GodotConfig);
const GodotFS = {
- $GodotFS__deps: ['$FS', '$IDBFS', '$GodotRuntime'],
+ $GodotFS__deps: ['$ERRNO_CODES', '$FS', '$IDBFS', '$GodotRuntime'],
$GodotFS__postset: [
'Module["initFS"] = GodotFS.init;',
'Module["copyToFS"] = GodotFS.copy_to_fs;',
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 76102d941b..95c5909d50 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -137,12 +137,12 @@ int OS_JavaScript::get_processor_count() const {
}
bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
- if (p_feature == "HTML5" || p_feature == "web") {
+ if (p_feature == "html5" || p_feature == "web") {
return true;
}
#ifdef JAVASCRIPT_EVAL_ENABLED
- if (p_feature == "JavaScript") {
+ if (p_feature == "javascript") {
return true;
}
#endif
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
new file mode 100644
index 0000000000..0d3fb37be5
--- /dev/null
+++ b/platform/linuxbsd/README.md
@@ -0,0 +1,11 @@
+# Linux/*BSD platform port
+
+This folder contains the C++ code for the Linux/*BSD platform port.
+
+## Artwork license
+
+[`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/):
+
+> Permission to use and/or modify this image is granted provided you acknowledge me
+ <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/)
+ if someone asks.
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index ea0222cb19..0e98af71fa 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "main/main.h"
#ifdef DEBUG_ENABLED
@@ -61,12 +63,19 @@ static void handle_crash(int sig) {
}
// Dump the backtrace to stderr with a message to the user
+ fprintf(stderr, "\n================================================================\n");
fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
if (OS::get_singleton()->get_main_loop()) {
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
}
+ // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
+ if (String(VERSION_HASH).length() != 0) {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n");
+ } else {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n");
+ }
fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
@@ -115,6 +124,7 @@ static void handle_crash(int sig) {
free(strings);
}
fprintf(stderr, "-- END OF BACKTRACE --\n");
+ fprintf(stderr, "================================================================\n");
// Abort to pass the error to the OS
abort();
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index 5c6be2d7d4..965a38ef4e 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -53,7 +53,7 @@ void register_linuxbsd_exporter() {
platform->set_debug_32("linux_x11_32_debug");
platform->set_release_64("linux_x11_64_release");
platform->set_debug_64("linux_x11_64_debug");
- platform->set_os_name("X11");
+ platform->set_os_name("LinuxBSD");
platform->set_chmod_flags(0755);
platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp
index 08630be8b0..2c9801f512 100644
--- a/platform/linuxbsd/os_linuxbsd.cpp
+++ b/platform/linuxbsd/os_linuxbsd.cpp
@@ -273,7 +273,7 @@ String OS_LinuxBSD::get_cache_path() const {
}
}
-String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const {
+String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
String xdgparam;
switch (p_dir) {
diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h
index 1e06587322..35c80e3f9b 100644
--- a/platform/linuxbsd/os_linuxbsd.h
+++ b/platform/linuxbsd/os_linuxbsd.h
@@ -84,7 +84,7 @@ public:
virtual String get_data_path() const override;
virtual String get_cache_path() const override;
- virtual String get_system_dir(SystemDir p_dir) const override;
+ virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
virtual Error shell_open(String p_uri) override;
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
index 0f128d504f..31228b10b4 100644
--- a/platform/osx/crash_handler_osx.mm
+++ b/platform/osx/crash_handler_osx.mm
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "main/main.h"
#include <string.h>
@@ -85,11 +87,18 @@ static void handle_crash(int sig) {
}
// Dump the backtrace to stderr with a message to the user
+ fprintf(stderr, "\n================================================================\n");
fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
if (OS::get_singleton()->get_main_loop())
OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH);
+ // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
+ if (String(VERSION_HASH).length() != 0) {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n");
+ } else {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n");
+ }
fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
char **strings = backtrace_symbols(bt_buffer, size);
if (strings) {
@@ -148,6 +157,7 @@ static void handle_crash(int sig) {
free(strings);
}
fprintf(stderr, "-- END OF BACKTRACE --\n");
+ fprintf(stderr, "================================================================\n");
// Abort to pass the error to the OS
abort();
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 43b7d7c1e0..f037d75fbd 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -190,6 +190,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
[wd.window_object setContentMinSize:NSMakeSize(0, 0)];
[wd.window_object setContentMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
+ // Force window resize event.
+ [self windowDidResize:notification];
}
- (void)windowDidExitFullScreen:(NSNotification *)notification {
@@ -217,6 +219,8 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) {
if (wd.on_top) {
[wd.window_object setLevel:NSFloatingWindowLevel];
}
+ // Force window resize event.
+ [self windowDidResize:notification];
}
- (void)windowDidChangeBackingProperties:(NSNotification *)notification {
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 5b959d6da4..54a3104482 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -931,7 +931,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
zipfi.tmz_date.tm_hour = time.hour;
zipfi.tmz_date.tm_mday = date.day;
zipfi.tmz_date.tm_min = time.minute;
- zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
zipfi.tmz_date.tm_sec = time.second;
zipfi.tmz_date.tm_year = date.year;
zipfi.dosDate = 0;
@@ -976,7 +976,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
zipfi.tmz_date.tm_hour = time.hour;
zipfi.tmz_date.tm_mday = date.day;
zipfi.tmz_date.tm_min = time.minute;
- zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, http://www.cplusplus.com/reference/ctime/tm/
+ zipfi.tmz_date.tm_mon = date.month - 1; // Note: "tm" month range - 0..11, Godot month range - 1..12, https://www.cplusplus.com/reference/ctime/tm/
zipfi.tmz_date.tm_sec = time.second;
zipfi.tmz_date.tm_year = date.year;
zipfi.dosDate = 0;
diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h
index cd85ce2aad..ca5086622e 100644
--- a/platform/osx/export/export_plugin.h
+++ b/platform/osx/export/export_plugin.h
@@ -115,7 +115,7 @@ public:
virtual void get_platform_features(List<String> *r_features) override {
r_features->push_back("pc");
r_features->push_back("s3tc");
- r_features->push_back("macOS");
+ r_features->push_back("macos");
}
virtual void resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) override {
diff --git a/platform/osx/joypad_osx.cpp b/platform/osx/joypad_osx.cpp
index d778271350..e67d2b0e91 100644
--- a/platform/osx/joypad_osx.cpp
+++ b/platform/osx/joypad_osx.cpp
@@ -143,6 +143,8 @@ void joypad::add_hid_element(IOHIDElementRef p_element) {
switch (usage) {
case kHIDUsage_Sim_Rudder:
case kHIDUsage_Sim_Throttle:
+ case kHIDUsage_Sim_Accelerator:
+ case kHIDUsage_Sim_Brake:
if (!has_element(cookie, &axis_elements)) {
list = &axis_elements;
}
@@ -332,6 +334,13 @@ bool JoypadOSX::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
p_joy->add_hid_elements(array);
CFRelease(array);
}
+ // Xbox controller hat values start at 1 rather than 0.
+ p_joy->offset_hat = vendor == 0x45e &&
+ (product_id == 0x0b05 ||
+ product_id == 0x02e0 ||
+ product_id == 0x02fd ||
+ product_id == 0x0b13);
+
return true;
}
@@ -388,13 +397,16 @@ bool joypad::check_ff_features() {
return false;
}
-static int process_hat_value(int p_min, int p_max, int p_value) {
+static int process_hat_value(int p_min, int p_max, int p_value, bool p_offset_hat) {
int range = (p_max - p_min + 1);
int value = p_value - p_min;
int hat_value = HatMask::HAT_MASK_CENTER;
if (range == 4) {
value *= 2;
}
+ if (p_offset_hat) {
+ value -= 1;
+ }
switch (value) {
case 0:
@@ -468,7 +480,7 @@ void JoypadOSX::process_joypads() {
for (int j = 0; j < joy.hat_elements.size(); j++) {
rec_element &elem = joy.hat_elements.write[j];
int value = joy.get_hid_element_state(&elem);
- int hat_value = process_hat_value(elem.min, elem.max, value);
+ int hat_value = process_hat_value(elem.min, elem.max, value, joy.offset_hat);
input->joy_hat(joy.id, (HatMask)hat_value);
}
diff --git a/platform/osx/joypad_osx.h b/platform/osx/joypad_osx.h
index bf7e8949df..c060c3d523 100644
--- a/platform/osx/joypad_osx.h
+++ b/platform/osx/joypad_osx.h
@@ -64,6 +64,7 @@ struct joypad {
Vector<rec_element> hat_elements;
int id = 0;
+ bool offset_hat = false;
io_service_t ffservice = 0; /* Interface for force feedback, 0 = no ff */
FFCONSTANTFORCE ff_constant_force;
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 37d30add78..df41ccd892 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -84,7 +84,7 @@ public:
virtual String get_bundle_resource_dir() const override;
virtual String get_godot_dir_name() const override;
- virtual String get_system_dir(SystemDir p_dir) const override;
+ virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
Error shell_open(String p_uri) override;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index c458a0264a..c6e35fee83 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -395,7 +395,7 @@ String OS_OSX::get_godot_dir_name() const {
return String(VERSION_SHORT_NAME).capitalize();
}
-String OS_OSX::get_system_dir(SystemDir p_dir) const {
+String OS_OSX::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
NSSearchPathDirectory id;
bool found = true;
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index 5bd00b1549..a54b85a803 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -485,7 +485,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
void EditorExportPlatformUWP::get_platform_features(List<String> *r_features) {
r_features->push_back("pc");
- r_features->push_back("UWP");
+ r_features->push_back("uwp");
}
void EditorExportPlatformUWP::resolve_platform_feature_priorities(const Ref<EditorExportPreset> &p_preset, Set<String> &p_features) {
diff --git a/platform/windows/crash_handler_windows.cpp b/platform/windows/crash_handler_windows.cpp
index e2d507eddd..1b4dae207f 100644
--- a/platform/windows/crash_handler_windows.cpp
+++ b/platform/windows/crash_handler_windows.cpp
@@ -32,6 +32,8 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
+#include "core/version.h"
+#include "core/version_hash.gen.h"
#include "main/main.h"
#ifdef CRASH_HANDLER_EXCEPTION
@@ -127,6 +129,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
return EXCEPTION_CONTINUE_SEARCH;
}
+ fprintf(stderr, "\n================================================================\n");
fprintf(stderr, "%s: Program crashed\n", __FUNCTION__);
if (OS::get_singleton()->get_main_loop())
@@ -175,6 +178,12 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
msg = proj_settings->get("debug/settings/crash_handler/message");
}
+ // Print the engine version just before, so that people are reminded to include the version in backtrace reports.
+ if (String(VERSION_HASH).length() != 0) {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n");
+ } else {
+ fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n");
+ }
fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data());
int n = 0;
@@ -200,6 +209,7 @@ DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
} while (frame.AddrReturn.Offset != 0 && n < 256);
fprintf(stderr, "-- END OF BACKTRACE --\n");
+ fprintf(stderr, "================================================================\n");
SymCleanup(process);
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 9154f7749e..3961480d23 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -321,7 +321,7 @@ def configure_msvc(env, manual_msvc_config):
def configure_mingw(env):
# Workaround for MinGW. See:
- # http://www.scons.org/wiki/LongCmdLinesOnWin32
+ # https://www.scons.org/wiki/LongCmdLinesOnWin32
env.use_windows_spawn_fix()
## Build type
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index b6489e7a95..1723026849 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -80,7 +80,7 @@ String DisplayServerWindows::get_name() const {
}
void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
- if (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN) {
+ if (windows.has(MAIN_WINDOW_ID) && (p_mode == MOUSE_MODE_CAPTURED || p_mode == MOUSE_MODE_CONFINED || p_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
// Mouse is grabbed (captured or confined).
WindowData &wd = windows[MAIN_WINDOW_ID];
@@ -118,8 +118,10 @@ void DisplayServerWindows::_set_mouse_mode_impl(MouseMode p_mode) {
void DisplayServerWindows::mouse_set_mode(MouseMode p_mode) {
_THREAD_SAFE_METHOD_
- if (mouse_mode == p_mode)
+ if (mouse_mode == p_mode) {
+ // Already in the same mode; do nothing.
return;
+ }
mouse_mode = p_mode;
@@ -134,7 +136,7 @@ void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return; //no window focused?
+ return; // No focused window?
}
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -154,7 +156,6 @@ Point2i DisplayServerWindows::mouse_get_position() const {
POINT p;
GetCursorPos(&p);
return Point2i(p.x, p.y);
- //return Point2(old_x, old_y);
}
MouseButton DisplayServerWindows::mouse_get_button_state() const {
@@ -165,12 +166,12 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return; //no window focused?
+ return; // No focused window?
}
- // Convert LF line endings to CRLF in clipboard content
- // Otherwise, line endings won't be visible when pasted in other software
- String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // avoid \r\r\n
+ // Convert LF line endings to CRLF in clipboard content.
+ // Otherwise, line endings won't be visible when pasted in other software.
+ String text = p_text.replace("\r\n", "\n").replace("\n", "\r\n"); // Avoid \r\r\n.
if (!OpenClipboard(windows[last_focused_window].hWnd)) {
ERR_FAIL_MSG("Unable to open clipboard.");
@@ -187,7 +188,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
SetClipboardData(CF_UNICODETEXT, mem);
- // set the CF_TEXT version (not needed?)
+ // Set the CF_TEXT version (not needed?).
CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
@@ -206,7 +207,7 @@ String DisplayServerWindows::clipboard_get() const {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
- return String(); //no window focused?
+ return String(); // No focused window?
}
String ret;
@@ -498,16 +499,18 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
}
void DisplayServerWindows::show_window(WindowID p_id) {
+ ERR_FAIL_COND(!windows.has(p_id));
+
WindowData &wd = windows[p_id];
if (p_id != MAIN_WINDOW_ID) {
_update_window_style(p_id);
}
- ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show The Window
+ ShowWindow(wd.hWnd, wd.no_focus ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
if (!wd.no_focus) {
- SetForegroundWindow(wd.hWnd); // Slightly Higher Priority
- SetFocus(wd.hWnd); // Sets Keyboard Focus To
+ SetForegroundWindow(wd.hWnd); // Slightly higher priority.
+ SetFocus(wd.hWnd); // Set keyboard focus.
}
}
@@ -606,6 +609,8 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p
}
void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
if (windows[p_window].mpath.size() == 0) {
SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
} else {
@@ -664,16 +669,11 @@ Point2i DisplayServerWindows::window_get_position(WindowID p_window) const {
ClientToScreen(wd.hWnd, &point);
return Point2i(point.x, point.y);
-
-#if 0
- //do not use this method, as it includes windows decorations
- RECT r;
- GetWindowRect(wd.hWnd, &r);
- return Point2(r.left, r.top);
-#endif
}
void DisplayServerWindows::_update_real_mouse_position(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
POINT mouse_pos;
if (GetCursorPos(&mouse_pos) && ScreenToClient(windows[p_window].hWnd, &mouse_pos)) {
if (mouse_pos.x > 0 && mouse_pos.y > 0 && mouse_pos.x <= windows[p_window].width && mouse_pos.y <= windows[p_window].height) {
@@ -691,14 +691,9 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
ERR_FAIL_COND(!windows.has(p_window));
WindowData &wd = windows[p_window];
- if (wd.fullscreen)
+ if (wd.fullscreen) {
return;
-#if 0
- //wrong needs to account properly for decorations
- RECT r;
- GetWindowRect(wd.hWnd, &r);
- MoveWindow(wd.hWnd, p_position.x, p_position.y, r.right - r.left, r.bottom - r.top, TRUE);
-#else
+ }
RECT rc;
rc.left = p_position.x;
@@ -711,8 +706,8 @@ void DisplayServerWindows::window_set_position(const Point2i &p_position, Window
AdjustWindowRectEx(&rc, style, false, exStyle);
MoveWindow(wd.hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE);
-#endif
- // Don't let the mouse leave the window when moved
+
+ // Don't let the mouse leave the window when moved.
if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT rect;
GetClientRect(wd.hWnd, &rect);
@@ -729,16 +724,15 @@ void DisplayServerWindows::window_set_transient(WindowID p_window, WindowID p_pa
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(p_window == p_parent);
-
ERR_FAIL_COND(!windows.has(p_window));
+
WindowData &wd_window = windows[p_window];
ERR_FAIL_COND(wd_window.transient_parent == p_parent);
-
ERR_FAIL_COND_MSG(wd_window.always_on_top, "Windows with the 'on top' can't become transient.");
if (p_parent == INVALID_WINDOW_ID) {
- //remove transient
+ // Remove transient.
ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID);
ERR_FAIL_COND(!windows.has(wd_window.transient_parent));
@@ -838,7 +832,7 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
MoveWindow(wd.hWnd, rect.left, rect.top, w, h, TRUE);
- // Don't let the mouse leave the window when resizing to a smaller resolution
+ // Don't let the mouse leave the window when resizing to a smaller resolution.
if (mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) {
RECT crect;
GetClientRect(wd.hWnd, &crect);
@@ -854,12 +848,13 @@ Size2i DisplayServerWindows::window_get_size(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), Size2i());
const WindowData &wd = windows[p_window];
+ // GetClientRect() returns a zero rect for a minimized window, so we need to get the size in another way.
if (wd.minimized) {
return Size2(wd.width, wd.height);
}
RECT r;
- if (GetClientRect(wd.hWnd, &r)) { // Only area inside of window border
+ if (GetClientRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
return Size2(r.right - r.left, r.bottom - r.top);
}
return Size2();
@@ -872,13 +867,17 @@ Size2i DisplayServerWindows::window_get_real_size(WindowID p_window) const {
const WindowData &wd = windows[p_window];
RECT r;
- if (GetWindowRect(wd.hWnd, &r)) { // Includes area of the window border
+ if (GetWindowRect(wd.hWnd, &r)) { // Retrieves area inside of window border, including decoration.
return Size2(r.right - r.left, r.bottom - r.top);
}
return Size2();
}
void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscreen, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex) {
+ // Windows docs for window styles:
+ // https://docs.microsoft.com/en-us/windows/win32/winmsg/window-styles
+ // https://docs.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles
+
r_style = 0;
r_style_ex = WS_EX_WINDOWEDGE;
if (p_main_window) {
@@ -886,10 +885,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
}
if (p_fullscreen || p_borderless) {
- r_style |= WS_POPUP;
- //if (p_borderless) {
- // r_style_ex |= WS_EX_TOOLWINDOW;
- //}
+ r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
} else {
if (p_resizable) {
if (p_maximized) {
@@ -1025,7 +1021,7 @@ bool DisplayServerWindows::window_is_maximize_allowed(WindowID p_window) const {
// FIXME: Implement this, or confirm that it should always be true.
- return true; //no idea
+ return true;
}
void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window) {
@@ -1170,8 +1166,9 @@ void DisplayServerWindows::window_set_ime_position(const Point2i &p_pos, WindowI
void DisplayServerWindows::console_set_visible(bool p_enabled) {
_THREAD_SAFE_METHOD_
- if (console_visible == p_enabled)
+ if (console_visible == p_enabled) {
return;
+ }
ShowWindow(GetConsoleWindow(), p_enabled ? SW_SHOW : SW_HIDE);
console_visible = p_enabled;
}
@@ -1185,8 +1182,9 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(p_shape, CURSOR_MAX);
- if (cursor_shape == p_shape)
+ if (cursor_shape == p_shape) {
return;
+ }
if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) {
cursor_shape = p_shape;
@@ -1196,7 +1194,7 @@ void DisplayServerWindows::cursor_set_shape(CursorShape p_shape) {
static const LPCTSTR win_cursors[CURSOR_MAX] = {
IDC_ARROW,
IDC_IBEAM,
- IDC_HAND, //finger
+ IDC_HAND, // Finger.
IDC_CROSS,
IDC_WAIT,
IDC_APPSTARTING,
@@ -1227,49 +1225,49 @@ DisplayServer::CursorShape DisplayServerWindows::cursor_get_shape() const {
}
void DisplayServerWindows::GetMaskBitmaps(HBITMAP hSourceBitmap, COLORREF clrTransparent, OUT HBITMAP &hAndMaskBitmap, OUT HBITMAP &hXorMaskBitmap) {
- // Get the system display DC
+ // Get the system display DC.
HDC hDC = GetDC(nullptr);
- // Create helper DC
+ // Create helper DC.
HDC hMainDC = CreateCompatibleDC(hDC);
HDC hAndMaskDC = CreateCompatibleDC(hDC);
HDC hXorMaskDC = CreateCompatibleDC(hDC);
- // Get the dimensions of the source bitmap
+ // Get the dimensions of the source bitmap.
BITMAP bm;
GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
- // Create the mask bitmaps
- hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
- hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // color
+ // Create the mask bitmaps.
+ hAndMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
+ hXorMaskBitmap = CreateCompatibleBitmap(hDC, bm.bmWidth, bm.bmHeight); // Color.
- // Release the system display DC
+ // Release the system display DC.
ReleaseDC(nullptr, hDC);
- // Select the bitmaps to helper DC
+ // Select the bitmaps to helper DC.
HBITMAP hOldMainBitmap = (HBITMAP)SelectObject(hMainDC, hSourceBitmap);
HBITMAP hOldAndMaskBitmap = (HBITMAP)SelectObject(hAndMaskDC, hAndMaskBitmap);
HBITMAP hOldXorMaskBitmap = (HBITMAP)SelectObject(hXorMaskDC, hXorMaskBitmap);
// Assign the monochrome AND mask bitmap pixels so that the pixels of the source bitmap
- // with 'clrTransparent' will be white pixels of the monochrome bitmap
+ // with 'clrTransparent' will be white pixels of the monochrome bitmap.
SetBkColor(hMainDC, clrTransparent);
BitBlt(hAndMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCCOPY);
// Assign the color XOR mask bitmap pixels so that the pixels of the source bitmap
// with 'clrTransparent' will be black and rest the pixels same as corresponding
- // pixels of the source bitmap
+ // pixels of the source bitmap.
SetBkColor(hXorMaskDC, RGB(0, 0, 0));
SetTextColor(hXorMaskDC, RGB(255, 255, 255));
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hAndMaskDC, 0, 0, SRCCOPY);
BitBlt(hXorMaskDC, 0, 0, bm.bmWidth, bm.bmHeight, hMainDC, 0, 0, SRCAND);
- // Deselect bitmaps from the helper DC
+ // Deselect bitmaps from the helper DC.
SelectObject(hMainDC, hOldMainBitmap);
SelectObject(hAndMaskDC, hOldAndMaskBitmap);
SelectObject(hXorMaskDC, hOldXorMaskBitmap);
- // Delete the helper DC
+ // Delete the helper DC.
DeleteDC(hXorMaskDC);
DeleteDC(hAndMaskDC);
DeleteDC(hMainDC);
@@ -1326,7 +1324,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
UINT image_size = texture_size.width * texture_size.height;
- // Create the BITMAP with alpha channel
+ // Create the BITMAP with alpha channel.
COLORREF *buffer = (COLORREF *)memalloc(sizeof(COLORREF) * image_size);
for (UINT index = 0; index < image_size; index++) {
@@ -1341,11 +1339,11 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
*(buffer + index) = image->get_pixel(column_index, row_index).to_argb32();
}
- // Using 4 channels, so 4 * 8 bits
+ // Using 4 channels, so 4 * 8 bits.
HBITMAP bitmap = CreateBitmap(texture_size.width, texture_size.height, 1, 4 * 8, buffer);
COLORREF clrTransparent = -1;
- // Create the AND and XOR masks for the bitmap
+ // Create the AND and XOR masks for the bitmap.
HBITMAP hAndMask = nullptr;
HBITMAP hXorMask = nullptr;
@@ -1357,7 +1355,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
return;
}
- // Finally, create the icon
+ // Finally, create the icon.
ICONINFO iconinfo;
iconinfo.fIcon = FALSE;
iconinfo.xHotspot = p_hotspot.x;
@@ -1365,8 +1363,9 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
iconinfo.hbmMask = hAndMask;
iconinfo.hbmColor = hXorMask;
- if (cursors[p_shape])
+ if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
+ }
cursors[p_shape] = CreateIconIndirect(&iconinfo);
@@ -1392,7 +1391,7 @@ void DisplayServerWindows::cursor_set_custom_image(const RES &p_cursor, CursorSh
memfree(buffer);
DeleteObject(bitmap);
} else {
- // Reset to default system cursor
+ // Reset to default system cursor.
if (cursors[p_shape]) {
DestroyIcon(cursors[p_shape]);
cursors[p_shape] = nullptr;
@@ -1574,9 +1573,9 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
icon_dir = (ICONDIR *)memrealloc(icon_dir, 3 * sizeof(WORD) + icon_dir->idCount * sizeof(ICONDIRENTRY));
f->get_buffer((uint8_t *)&icon_dir->idEntries[0], icon_dir->idCount * sizeof(ICONDIRENTRY));
- int small_icon_index = -1; // Select 16x16 with largest color count
+ int small_icon_index = -1; // Select 16x16 with largest color count.
int small_icon_cc = 0;
- int big_icon_index = -1; // Select largest
+ int big_icon_index = -1; // Select largest.
int big_icon_width = 16;
int big_icon_cc = 0;
@@ -1606,7 +1605,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
small_icon_cc = big_icon_cc;
}
- // Read the big icon
+ // Read the big icon.
DWORD bytecount_big = icon_dir->idEntries[big_icon_index].dwBytesInRes;
Vector<uint8_t> data_big;
data_big.resize(bytecount_big);
@@ -1616,7 +1615,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
HICON icon_big = CreateIconFromResource((PBYTE)&data_big.write[0], bytecount_big, TRUE, 0x00030000);
ERR_FAIL_COND_MSG(!icon_big, "Could not create " + itos(big_icon_width) + "x" + itos(big_icon_width) + " @" + itos(big_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
- // Read the small icon
+ // Read the small icon.
DWORD bytecount_small = icon_dir->idEntries[small_icon_index].dwBytesInRes;
Vector<uint8_t> data_small;
data_small.resize(bytecount_small);
@@ -1626,7 +1625,7 @@ void DisplayServerWindows::set_native_icon(const String &p_filename) {
HICON icon_small = CreateIconFromResource((PBYTE)&data_small.write[0], bytecount_small, TRUE, 0x00030000);
ERR_FAIL_COND_MSG(!icon_small, "Could not create 16x16 @" + itos(small_icon_cc) + " icon, error: " + format_error_message(GetLastError()) + ".");
- // Online tradition says to be sure last error is cleared and set the small icon first
+ // Online tradition says to be sure last error is cleared and set the small icon first.
int err = 0;
SetLastError(err);
@@ -1647,12 +1646,13 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
ERR_FAIL_COND(!p_icon.is_valid());
Ref<Image> icon = p_icon->duplicate();
- if (icon->get_format() != Image::FORMAT_RGBA8)
+ if (icon->get_format() != Image::FORMAT_RGBA8) {
icon->convert(Image::FORMAT_RGBA8);
+ }
int w = icon->get_width();
int h = icon->get_height();
- /* Create temporary bitmap buffer */
+ // Create temporary bitmap buffer.
int icon_len = 40 + h * w * 4;
Vector<BYTE> v;
v.resize(icon_len);
@@ -1686,10 +1686,10 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
- /* Set the icon for the window */
+ // Set the icon for the window.
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hicon);
- /* Set the icon in the task manager (should we do this?) */
+ // Set the icon in the task manager (should we do this?).
SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_SETICON, ICON_BIG, (LPARAM)hicon);
}
@@ -1717,13 +1717,13 @@ void DisplayServerWindows::set_context(Context p_context) {
// Keeping the name suggested by Microsoft, but this macro really answers:
// Is this mouse event emulated from touch or pen input?
#define IsPenEvent(dw) (((dw)&SIGNATURE_MASK) == MI_WP_SIGNATURE)
-// This one tells whether the event comes from touchscreen (and not from pen)
+// This one tells whether the event comes from touchscreen (and not from pen).
#define IsTouchEvent(dw) (IsPenEvent(dw) && ((dw)&0x80))
void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx) {
- // Defensive
- if (touch_state.has(idx) == p_pressed)
+ if (touch_state.has(idx) == p_pressed) {
return;
+ }
if (p_pressed) {
touch_state.insert(idx, Vector2(p_x, p_y));
@@ -1743,12 +1743,13 @@ void DisplayServerWindows::_touch_event(WindowID p_window, bool p_pressed, float
void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y, int idx) {
Map<int, Vector2>::Element *curr = touch_state.find(idx);
- // Defensive
- if (!curr)
+ if (!curr) {
return;
+ }
- if (curr->get() == Vector2(p_x, p_y))
+ if (curr->get() == Vector2(p_x, p_y)) {
return;
+ }
Ref<InputEventScreenDrag> event;
event.instantiate();
@@ -1790,7 +1791,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
Ref<InputEventFromWindow> event_from_window = p_event;
if (event_from_window.is_valid() && event_from_window->get_window_id() != INVALID_WINDOW_ID) {
- //send to a window
+ // Send to a single window.
if (!windows.has(event_from_window->get_window_id())) {
in_dispatch_input_event = false;
ERR_FAIL_MSG("DisplayServerWindows: Invalid window id in input event.");
@@ -1802,7 +1803,7 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
}
callable.call((const Variant **)&evp, 1, ret, ce);
} else {
- //send to all windows
+ // Send to all windows.
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
Callable callable = E->get().input_event_callback;
if (callable.is_null()) {
@@ -1815,6 +1816,9 @@ void DisplayServerWindows::_dispatch_input_event(const Ref<InputEvent> &p_event)
in_dispatch_input_event = false;
}
+// Our default window procedure to handle processing of window-related system messages/events.
+// Also known as DefProc or DefWindowProc.
+// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (drop_events) {
if (user_proc) {
@@ -1827,6 +1831,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
WindowID window_id = INVALID_WINDOW_ID;
bool window_created = false;
+ // Check whether window exists.
for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
if (E->get().hWnd == hWnd) {
window_id = E->key();
@@ -1835,19 +1840,19 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
+ // Window doesn't exist or creation in progress, don't handle messages yet.
if (!window_created) {
- // Window creation in progress.
window_id = window_id_counter;
ERR_FAIL_COND_V(!windows.has(window_id), 0);
}
- switch (uMsg) // Check For Windows Messages
- {
+ // Process window messages.
+ switch (uMsg) {
case WM_SETFOCUS: {
windows[window_id].window_has_focus = true;
last_focused_window = window_id;
- // Restore mouse mode
+ // Restore mouse mode.
_set_mouse_mode_impl(mouse_mode);
if (!app_focused) {
@@ -1856,16 +1861,15 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
app_focused = true;
}
- break;
- }
+ } break;
case WM_KILLFOCUS: {
windows[window_id].window_has_focus = false;
last_focused_window = window_id;
- // Release capture unconditionally because it can be set due to dragging, in addition to captured mode
+ // Release capture unconditionally because it can be set due to dragging, in addition to captured mode.
ReleaseCapture();
- // Release every touch to avoid sticky points
+ // Release every touch to avoid sticky points.
for (Map<int, Vector2>::Element *E = touch_state.front(); E; E = E->next()) {
_touch_event(window_id, false, E->get().x, E->get().y, E->key());
}
@@ -1883,10 +1887,8 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
app_focused = false;
}
-
- break;
- }
- case WM_ACTIVATE: { // Watch For Window Activate Message
+ } break;
+ case WM_ACTIVATE: { // Watch for window activate message.
if (!windows[window_id].window_focused) {
_process_activate_event(window_id, wParam, lParam);
} else {
@@ -1896,11 +1898,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Run a timer to prevent event catching warning if the focused window is closing.
windows[window_id].focus_timer_id = SetTimer(windows[window_id].hWnd, 2, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
}
- return 0; // Return To The Message Loop
- }
+ return 0; // Return to the message loop.
+ } break;
case WM_GETMINMAXINFO: {
if (windows[window_id].resizable && !windows[window_id].fullscreen) {
- Size2 decor = window_get_size(window_id) - window_get_real_size(window_id); // Size of window decorations
+ // Size of window decorations.
+ Size2 decor = window_get_real_size(window_id) - window_get_size(window_id);
+
MINMAXINFO *min_max_info = (MINMAXINFO *)lParam;
if (windows[window_id].min_size != Size2()) {
min_max_info->ptMinTrackSize.x = windows[window_id].min_size.x + decor.x;
@@ -1911,37 +1915,31 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
min_max_info->ptMaxTrackSize.y = windows[window_id].max_size.y + decor.y;
}
return 0;
- } else {
- break;
}
- }
- case WM_PAINT:
-
+ } break;
+ case WM_PAINT: {
Main::force_redraw();
- break;
-
- case WM_SYSCOMMAND: // Intercept System Commands
+ } break;
+ case WM_SYSCOMMAND: // Intercept system commands.
{
- switch (wParam) // Check System Calls
+ switch (wParam) // Check system calls.
{
- case SC_SCREENSAVE: // Screensaver Trying To Start?
- case SC_MONITORPOWER: // Monitor Trying To Enter Powersave?
- return 0; // Prevent From Happening
+ case SC_SCREENSAVE: // Screensaver trying to start?
+ case SC_MONITORPOWER: // Monitor trying to enter powersave?
+ return 0; // Prevent from happening.
case SC_KEYMENU:
if ((lParam >> 16) <= 0)
return 0;
}
- break; // Exit
- }
-
- case WM_CLOSE: // Did We Receive A Close Message?
+ } break;
+ case WM_CLOSE: // Did we receive a close message?
{
if (windows[window_id].focus_timer_id != 0U) {
KillTimer(windows[window_id].hWnd, windows[window_id].focus_timer_id);
}
_send_window_event(windows[window_id], WINDOW_EVENT_CLOSE_REQUEST);
- return 0; // Jump Back
+ return 0; // Jump back.
}
case WM_MOUSELEAVE: {
old_invalid = true;
@@ -1983,7 +1981,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Point2i c(windows[window_id].width / 2, windows[window_id].height / 2);
- // centering just so it works as before
+ // Centering just so it works as before.
POINT pos = { (int)c.x, (int)c.y };
ClientToScreen(windows[window_id].hWnd, &pos);
SetCursorPos(pos.x, pos.y);
@@ -2006,7 +2004,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
(double(raw->data.mouse.lLastX) - 65536.0 / (nScreenWidth)) * nScreenWidth / 65536.0 + nScreenLeft,
(double(raw->data.mouse.lLastY) - 65536.0 / (nScreenHeight)) * nScreenHeight / 65536.0 + nScreenTop);
- POINT coords; //client coords
+ POINT coords; // Client coords.
coords.x = abs_pos.x;
coords.y = abs_pos.y;
@@ -2015,14 +2013,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_relative(Vector2(coords.x - old_x, coords.y - old_y));
old_x = coords.x;
old_y = coords.y;
-
- /*Input.mi.dx = (int)((((double)(pos.x)-nScreenLeft) * 65536) / nScreenWidth + 65536 / (nScreenWidth));
- Input.mi.dy = (int)((((double)(pos.y)-nScreenTop) * 65536) / nScreenHeight + 65536 / (nScreenHeight));
- */
}
- if (windows[window_id].window_has_focus && mm->get_relative() != Vector2())
+ if (windows[window_id].window_has_focus && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
+ }
}
delete[] lpb;
} break;
@@ -2167,7 +2162,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
+ // Universal translation enabled; ignore OS translation.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2175,7 +2170,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (outside) {
- //mouse enter
+ // Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
@@ -2186,7 +2181,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
cursor_set_shape(c);
outside = false;
- //Once-Off notification, must call again....
+ // Once-off notification, must call again.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -2219,7 +2214,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_button_mask(last_button_state);
- POINT coords; //client coords
+ POINT coords; // Client coords.
coords.x = GET_X_LPARAM(lParam);
coords.y = GET_Y_LPARAM(lParam);
@@ -2261,7 +2256,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Input::get_singleton()->parse_input_event(mm);
}
- return 0; //Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event
+ return 0; // Pointer event handled return 0 to avoid duplicate WM_MOUSEMOVE event.
} break;
case WM_MOUSEMOVE: {
if (windows[window_id].block_mm) {
@@ -2273,7 +2268,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translation
+ // Universal translation enabled; ignore OS translation.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2281,7 +2276,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
if (outside) {
- //mouse enter
+ // Mouse enter.
if (mouse_mode != MOUSE_MODE_CAPTURED) {
_send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER);
@@ -2292,7 +2287,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
cursor_set_shape(c);
outside = false;
- //Once-Off notification, must call again....
+ // Once-off notification, must call again.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -2370,7 +2365,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
if (Input::get_singleton()->is_emulating_mouse_from_touch()) {
- // Universal translation enabled; ignore OS translations for left button
+ // Universal translation enabled; ignore OS translations for left button.
LPARAM extra = GetMessageExtraInfo();
if (IsTouchEvent(extra)) {
break;
@@ -2494,7 +2489,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mb->set_ctrl_pressed((wParam & MK_CONTROL) != 0);
mb->set_shift_pressed((wParam & MK_SHIFT) != 0);
mb->set_alt_pressed(alt_mem);
- //mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
+ // mb->is_alt_pressed()=(wParam&MK_MENU)!=0;
if (mb->is_pressed()) {
last_button_state |= MouseButton(1 << (mb->get_button_index() - 1));
} else {
@@ -2521,7 +2516,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
} else {
- // for reasons unknown to mankind, wheel comes in screen coordinates
+ // For reasons unknown to mankind, wheel comes in screen coordinates.
POINT coords;
coords.x = mb->get_position().x;
coords.y = mb->get_position().y;
@@ -2535,7 +2530,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Input::get_singleton()->parse_input_event(mb);
if (mb->is_pressed() && mb->get_button_index() > 3 && mb->get_button_index() < 8) {
- //send release for mouse wheel
+ // Send release for mouse wheel.
Ref<InputEventMouseButton> mbd = mb->duplicate();
mbd->set_window_id(window_id);
last_button_state &= (MouseButton) ~(1 << (mbd->get_button_index() - 1));
@@ -2545,7 +2540,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
} break;
-
case WM_MOVE: {
if (!IsIconic(windows[window_id].hWnd)) {
int x = int16_t(LOWORD(lParam));
@@ -2561,12 +2555,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
} break;
-
case WM_SIZE: {
- // Ignore size when a SIZE_MINIMIZED event is triggered
+ // Ignore window size change when a SIZE_MINIMIZED event is triggered.
if (wParam != SIZE_MINIMIZED) {
+ // The new width and height of the client area.
int window_w = LOWORD(lParam);
int window_h = HIWORD(lParam);
+
+ // Set new value to the size if it isn't preserved.
if (window_w > 0 && window_h > 0 && !windows[window_id].preserve_window_size) {
windows[window_id].width = window_w;
windows[window_id].height = window_h;
@@ -2577,29 +2573,38 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
#endif
- } else {
+ } else { // If the size is preserved.
windows[window_id].preserve_window_size = false;
+
+ // Restore the old size.
window_set_size(Size2(windows[window_id].width, windows[window_id].height), window_id);
}
- } else {
+ } else { // When the window has been minimized, preserve its size.
windows[window_id].preserve_window_size = true;
}
+ // Call windows rect change callback.
if (!windows[window_id].rect_changed_callback.is_null()) {
Variant size = Rect2i(windows[window_id].last_pos.x, windows[window_id].last_pos.y, windows[window_id].width, windows[window_id].height);
- Variant *sizep = &size;
+ Variant *size_ptr = &size;
Variant ret;
Callable::CallError ce;
- windows[window_id].rect_changed_callback.call((const Variant **)&sizep, 1, ret, ce);
+ windows[window_id].rect_changed_callback.call((const Variant **)&size_ptr, 1, ret, ce);
}
+ // The window has been maximized.
if (wParam == SIZE_MAXIMIZED) {
windows[window_id].maximized = true;
windows[window_id].minimized = false;
- } else if (wParam == SIZE_MINIMIZED) {
+ }
+ // The window has been minimized.
+ else if (wParam == SIZE_MINIMIZED) {
windows[window_id].maximized = false;
windows[window_id].minimized = true;
- } else if (wParam == SIZE_RESTORED) {
+ windows[window_id].preserve_window_size = false;
+ }
+ // The window has been resized, but neither the SIZE_MINIMIZED nor SIZE_MAXIMIZED value applies.
+ else if (wParam == SIZE_RESTORED) {
windows[window_id].maximized = false;
windows[window_id].minimized = false;
}
@@ -2626,9 +2631,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
ZeroMemory(dib_data, dib_size.x * dib_size.y * 4);
}
#endif
- //return 0; // Jump Back
} break;
-
case WM_ENTERSIZEMOVE: {
Input::get_singleton()->release_pressed_events();
windows[window_id].move_timer_id = SetTimer(windows[window_id].hWnd, 1, USER_TIMER_MINIMUM, (TIMERPROC) nullptr);
@@ -2648,7 +2651,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
windows[window_id].focus_timer_id = 0U;
}
} break;
-
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYUP:
@@ -2700,7 +2702,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
case WM_INPUTLANGCHANGEREQUEST: {
// FIXME: Do something?
} break;
-
case WM_TOUCH: {
BOOL bHandled = FALSE;
UINT cInputs = LOWORD(wParam);
@@ -2714,7 +2715,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
TOUCH_COORD_TO_PIXEL(ti.y),
};
ScreenToClient(hWnd, &touch_pos);
- //do something with each touch input entry
+ // Do something with each touch input entry.
if (ti.dwFlags & TOUCHEVENTF_MOVE) {
_drag_event(window_id, touch_pos.x, touch_pos.y, ti.dwID);
} else if (ti.dwFlags & (TOUCHEVENTF_UP | TOUCHEVENTF_DOWN)) {
@@ -2723,11 +2724,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
bHandled = TRUE;
} else {
- /* handle the error here */
+ // TODO: Handle the error here.
}
memdelete_arr(pInputs);
} else {
- /* handle the error here, probably out of memory */
+ // TODO: Handle the error here, probably out of memory.
}
if (bHandled) {
CloseTouchInputHandle((HTOUCHINPUT)lParam);
@@ -2735,14 +2736,13 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
};
} break;
-
case WM_DEVICECHANGE: {
joypad->probe_joypads();
} break;
case WM_SETCURSOR: {
if (LOWORD(lParam) == HTCLIENT) {
if (windows[window_id].window_has_focus && (mouse_mode == MOUSE_MODE_HIDDEN || mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN)) {
- //Hide the cursor
+ // Hide the cursor.
if (hCursor == nullptr) {
hCursor = SetCursor(nullptr);
} else {
@@ -2757,7 +2757,6 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
}
-
} break;
case WM_DROPFILES: {
HDROP hDropInfo = (HDROP)wParam;
@@ -2781,9 +2780,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
Callable::CallError ce;
windows[window_id].drop_files_callback.call((const Variant **)&vp, 1, ret, ce);
}
-
} break;
-
default: {
if (user_proc) {
return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
@@ -2809,7 +2806,7 @@ void DisplayServerWindows::_process_activate_event(WindowID p_window_id, WPARAM
alt_mem = false;
control_mem = false;
shift_mem = false;
- } else { // WM_INACTIVE
+ } else { // WM_INACTIVE.
Input::get_singleton()->release_pressed_events();
_send_window_event(windows[p_window_id], WINDOW_EVENT_FOCUS_OUT);
windows[p_window_id].window_focused = false;
@@ -2826,7 +2823,7 @@ void DisplayServerWindows::_process_key_events() {
KeyEvent &ke = key_event_buffer[i];
switch (ke.uMsg) {
case WM_CHAR: {
- // extended keys should only be processed as WM_KEYDOWN message.
+ // Extended keys should only be processed as WM_KEYDOWN message.
if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) {
static char32_t prev_wc = 0;
char32_t unicode = ke.wParam;
@@ -2867,9 +2864,9 @@ void DisplayServerWindows::_process_key_events() {
k->set_unicode(0);
Input::get_singleton()->parse_input_event(k);
+ } else {
+ // Do nothing.
}
-
- //do nothing
} break;
case WM_KEYUP:
case WM_KEYDOWN: {
@@ -2885,7 +2882,7 @@ void DisplayServerWindows::_process_key_events() {
k->set_pressed(ke.uMsg == WM_KEYDOWN);
if ((ke.lParam & (1 << 24)) && (ke.wParam == VK_RETURN)) {
- // Special case for Numpad Enter key
+ // Special case for Numpad Enter key.
k->set_keycode(KEY_KP_ENTER);
} else {
k->set_keycode((Key)KeyMappingWindows::get_keysym(ke.wParam));
@@ -3031,8 +3028,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
if (p_mode != WINDOW_MODE_FULLSCREEN) {
wd.pre_fs_valid = true;
}
-#ifdef VULKAN_ENABLED
+#ifdef VULKAN_ENABLED
if (rendering_driver == "vulkan") {
if (context_vulkan->window_create(id, p_vsync_mode, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) == -1) {
memdelete(context_vulkan);
@@ -3087,7 +3084,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wd.last_pressure_update = 0;
wd.last_tilt = Vector2();
- // IME
+ // IME.
wd.im_himc = ImmGetContext(wd.hWnd);
ImmReleaseContext(wd.hWnd, wd.im_himc);
@@ -3102,7 +3099,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
return id;
}
-// WinTab API
+// WinTab API.
bool DisplayServerWindows::wintab_available = false;
WTOpenPtr DisplayServerWindows::wintab_WTOpen = nullptr;
WTClosePtr DisplayServerWindows::wintab_WTClose = nullptr;
@@ -3110,7 +3107,7 @@ WTInfoPtr DisplayServerWindows::wintab_WTInfo = nullptr;
WTPacketPtr DisplayServerWindows::wintab_WTPacket = nullptr;
WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
-// Windows Ink API
+// Windows Ink API.
bool DisplayServerWindows::winink_available = false;
GetPointerTypePtr DisplayServerWindows::win8p_GetPointerType = nullptr;
GetPointerPenInfoPtr DisplayServerWindows::win8p_GetPointerPenInfo = nullptr;
@@ -3173,7 +3170,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
outside = true;
- //Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
+ // Note: Wacom WinTab driver API for pen input, for devices incompatible with Windows Ink.
HMODULE wintab_lib = LoadLibraryW(L"wintab32.dll");
if (wintab_lib) {
wintab_WTOpen = (WTOpenPtr)GetProcAddress(wintab_lib, "WTOpenW");
@@ -3189,7 +3186,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
tablet_drivers.push_back("wintab");
}
- //Note: Windows Ink API for pen input, available on Windows 8+ only.
+ // Note: Windows Ink API for pen input, available on Windows 8+ only.
HMODULE user32_lib = LoadLibraryW(L"user32.dll");
if (user32_lib) {
win8p_GetPointerType = (GetPointerTypePtr)GetProcAddress(user32_lib, "GetPointerType");
@@ -3222,7 +3219,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
wc.lpfnWndProc = (WNDPROC)::WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
- //wc.hInstance = hInstance;
wc.hInstance = hInstance ? hInstance : GetModuleHandle(nullptr);
wc.hIcon = LoadIcon(nullptr, IDI_WINLOGO);
wc.hCursor = nullptr; //LoadCursor(nullptr, IDC_ARROW);
@@ -3246,7 +3242,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
Rid[0].hwndTarget = 0;
if (RegisterRawInputDevices(Rid, 1, sizeof(Rid[0])) == FALSE) {
- //registration failed.
+ // Registration failed.
use_raw_input = false;
}
@@ -3263,6 +3259,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
#endif
+
#if defined(OPENGL_ENABLED)
if (rendering_driver_index == VIDEO_DRIVER_GLES2) {
context_gles2 = memnew(ContextGL_Windows(hWnd, false));
@@ -3285,6 +3282,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
}
}
#endif
+
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
(screen_get_size(0).height - p_resolution.height) / 2);
@@ -3313,7 +3311,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
//set_ime_active(false);
if (!OS::get_singleton()->is_in_low_processor_usage_mode()) {
- //SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
DWORD index = 0;
HANDLE handle = AvSetMmThreadCharacteristics("Games", &index);
@@ -3321,7 +3318,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
AvSetMmThreadPriority(handle, AVRT_PRIORITY_CRITICAL);
// This is needed to make sure that background work does not starve the main thread.
- // This is only setting priority of this thread, not the whole process.
+ // This is only setting the priority of this thread, not the whole process.
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
}
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 2c8afaf7de..2a0a509d43 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -681,7 +681,7 @@ String OS_Windows::get_godot_dir_name() const {
return String(VERSION_SHORT_NAME).capitalize();
}
-String OS_Windows::get_system_dir(SystemDir p_dir) const {
+String OS_Windows::get_system_dir(SystemDir p_dir, bool p_shared_storage) const {
KNOWNFOLDERID id;
switch (p_dir) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index ea0c263b78..c4a2eda8f4 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -150,7 +150,7 @@ public:
virtual String get_cache_path() const override;
virtual String get_godot_dir_name() const override;
- virtual String get_system_dir(SystemDir p_dir) const override;
+ virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override;
virtual String get_user_data_dir() const override;
virtual String get_unique_id() const override;