summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/export/export_plugin.cpp14
-rw-r--r--platform/android/export/export_plugin.h2
-rw-r--r--platform/android/java/app/config.gradle15
-rw-r--r--platform/android/java/build.gradle4
-rw-r--r--platform/android/java/lib/build.gradle17
-rw-r--r--platform/android/java/scripts/publish-module.gradle74
-rw-r--r--platform/android/java/scripts/publish-root.gradle39
-rw-r--r--platform/iphone/export/export_plugin.cpp2
-rw-r--r--platform/javascript/display_server_javascript.cpp2
-rw-r--r--platform/javascript/export/export_plugin.cpp2
-rw-r--r--platform/linuxbsd/export/export.cpp117
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp200
-rw-r--r--platform/linuxbsd/export/export_plugin.h51
-rw-r--r--platform/osx/display_server_osx.h39
-rw-r--r--platform/osx/display_server_osx.mm535
-rw-r--r--platform/osx/export/export_plugin.cpp84
-rw-r--r--platform/osx/export/export_plugin.h3
-rw-r--r--platform/osx/godot_menu_item.h11
-rw-r--r--platform/uwp/export/export_plugin.cpp2
-rw-r--r--platform/windows/display_server_windows.cpp10
-rw-r--r--platform/windows/export/export.cpp75
-rw-r--r--platform/windows/export/export_plugin.cpp106
-rw-r--r--platform/windows/export/export_plugin.h3
-rw-r--r--platform/windows/godot.icobin110755 -> 359559 bytes
-rw-r--r--platform/windows/os_windows.cpp14
25 files changed, 1156 insertions, 265 deletions
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 4220c57cae..df3693ba61 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -2256,9 +2256,9 @@ String EditorExportPlatformAndroid::get_apk_expansion_fullpath(const Ref<EditorE
return fullpath;
}
-Error EditorExportPlatformAndroid::save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+Error EditorExportPlatformAndroid::save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) {
String fullpath = get_apk_expansion_fullpath(p_preset, p_path);
- Error err = save_pack(p_preset, fullpath);
+ Error err = save_pack(p_preset, p_debug, fullpath);
return err;
}
@@ -2576,7 +2576,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
CustomExportData user_data;
user_data.assets_directory = assets_directory;
user_data.debug = p_debug;
- err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
+ err = export_project_files(p_preset, p_debug, rename_and_store_file_in_gradle_project, &user_data, copy_gradle_so);
if (err != OK) {
EditorNode::add_io_error(TTR("Could not export project files to gradle project\n"));
return err;
@@ -2589,7 +2589,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
}
} else {
print_verbose("Saving apk expansion file..");
- err = save_apk_expansion_file(p_preset, p_path);
+ err = save_apk_expansion_file(p_preset, p_debug, p_path);
if (err != OK) {
EditorNode::add_io_error(TTR("Could not write expansion package file!"));
return err;
@@ -2915,10 +2915,10 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
APKExportData ed;
ed.ep = &ep;
ed.apk = unaligned_apk;
- err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
+ err = export_project_files(p_preset, p_debug, ignore_apk_file, &ed, save_apk_so);
} else {
if (apk_expansion) {
- err = save_apk_expansion_file(p_preset, p_path);
+ err = save_apk_expansion_file(p_preset, p_debug, p_path);
if (err != OK) {
EditorNode::add_io_error(TTR("Could not write expansion package file!"));
return err;
@@ -2927,7 +2927,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP
APKExportData ed;
ed.ep = &ep;
ed.apk = unaligned_apk;
- err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
+ err = export_project_files(p_preset, p_debug, save_apk_file, &ed, save_apk_so);
}
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index a4eb608b19..0f267cf13a 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -210,7 +210,7 @@ public:
String get_apk_expansion_fullpath(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error save_apk_expansion_file(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);
void get_command_line_flags(const Ref<EditorExportPreset> &p_preset, const String &p_path, int p_flags, Vector<uint8_t> &r_command_line_flags);
diff --git a/platform/android/java/app/config.gradle b/platform/android/java/app/config.gradle
index 32e03998da..c238d1b361 100644
--- a/platform/android/java/app/config.gradle
+++ b/platform/android/java/app/config.gradle
@@ -4,7 +4,7 @@ ext.versions = [
minSdk : 19, // Also update 'platform/android/java/lib/AndroidManifest.xml#minSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
targetSdk : 30, // Also update 'platform/android/java/lib/AndroidManifest.xml#targetSdkVersion' & 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
buildTools : '30.0.3',
- kotlinVersion : '1.5.10',
+ kotlinVersion : '1.6.10',
fragmentVersion : '1.3.6',
javaVersion : 11,
ndkVersion : '21.4.7075529' // Also update 'platform/android/detect.py#get_project_ndk_version()' when this is updated.
@@ -86,13 +86,12 @@ ext.getGodotEditorVersion = { ->
return editorVersion
}
-ext.getGodotLibraryVersion = { ->
+ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
// Attempt to read the version from the `version.py` file.
String libraryVersion = ""
File versionFile = new File("../../../version.py")
if (versionFile.isFile()) {
- List<String> requiredKeys = ["major", "minor", "patch", "status", "module_config"]
def map = [:]
List<String> lines = versionFile.readLines()
@@ -121,6 +120,16 @@ ext.getGodotLibraryVersion = { ->
return libraryVersion
}
+ext.getGodotLibraryVersion = { ->
+ List<String> requiredKeys = ["major", "minor", "patch", "status", "module_config"]
+ return generateGodotLibraryVersion(requiredKeys)
+}
+
+ext.getGodotPublishVersion = { ->
+ List<String> requiredKeys = ["major", "minor", "patch", "status"]
+ return generateGodotLibraryVersion(requiredKeys)
+}
+
final String VALUE_SEPARATOR_REGEX = "\\|"
// get the list of ABIs the project should be exported to
diff --git a/platform/android/java/build.gradle b/platform/android/java/build.gradle
index ac008edbed..83bc68c992 100644
--- a/platform/android/java/build.gradle
+++ b/platform/android/java/build.gradle
@@ -1,4 +1,6 @@
+apply plugin: 'io.github.gradle-nexus.publish-plugin'
apply from: 'app/config.gradle'
+apply from: 'scripts/publish-root.gradle'
buildscript {
apply from: 'app/config.gradle'
@@ -6,10 +8,12 @@ buildscript {
repositories {
google()
mavenCentral()
+ maven { url "https://plugins.gradle.org/m2/" }
}
dependencies {
classpath libraries.androidGradlePlugin
classpath libraries.kotlinGradlePlugin
+ classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
}
}
diff --git a/platform/android/java/lib/build.gradle b/platform/android/java/lib/build.gradle
index fbed4ed078..120a40a31d 100644
--- a/platform/android/java/lib/build.gradle
+++ b/platform/android/java/lib/build.gradle
@@ -1,6 +1,13 @@
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
+ext {
+ PUBLISH_VERSION = getGodotPublishVersion()
+ PUBLISH_ARTIFACT_ID = 'godot'
+}
+
+apply from: "../scripts/publish-module.gradle"
+
dependencies {
implementation libraries.kotlinStdLib
implementation libraries.androidxFragment
@@ -21,6 +28,8 @@ android {
manifestPlaceholders = [godotLibraryVersion: getGodotLibraryVersion()]
}
+ namespace = "org.godotengine.godot"
+
compileOptions {
sourceCompatibility versions.javaVersion
targetCompatibility versions.javaVersion
@@ -111,4 +120,12 @@ android {
// Schedule the tasks so the generated libs are present before the aar file is packaged.
tasks["merge${buildType}JniLibFolders"].dependsOn taskName
}
+
+ // TODO: Enable when issues with AGP 7.1+ are resolved (https://github.com/GodotVR/godot_openxr/issues/187).
+// publishing {
+// singleVariant("release") {
+// withSourcesJar()
+// withJavadocJar()
+// }
+// }
}
diff --git a/platform/android/java/scripts/publish-module.gradle b/platform/android/java/scripts/publish-module.gradle
new file mode 100644
index 0000000000..6b2aea5caf
--- /dev/null
+++ b/platform/android/java/scripts/publish-module.gradle
@@ -0,0 +1,74 @@
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+group = ossrhGroupId
+version = PUBLISH_VERSION
+
+afterEvaluate {
+ publishing {
+ publications {
+ release(MavenPublication) {
+ // The coordinates of the library, being set from variables that
+ // we'll set up later
+ groupId ossrhGroupId
+ artifactId PUBLISH_ARTIFACT_ID
+ version PUBLISH_VERSION
+
+ // Two artifacts, the `aar` (or `jar`) and the sources
+ if (project.plugins.findPlugin("com.android.library")) {
+ from components.release
+ } else {
+ from components.java
+ }
+
+ // Mostly self-explanatory metadata
+ pom {
+ name = PUBLISH_ARTIFACT_ID
+ description = 'Godot Engine Android Library'
+ url = 'https://godotengine.org/'
+ licenses {
+ license {
+ name = 'MIT License'
+ url = 'https://github.com/godotengine/godot/blob/master/LICENSE.txt'
+ }
+ }
+ developers {
+ developer {
+ id = 'm4gr3d'
+ name = 'Fredia Huya-Kouadio'
+ email = 'fhuyakou@gmail.com'
+ }
+ developer {
+ id = 'reduz'
+ name = 'Juan Linietsky'
+ email = 'reduzio@gmail.com'
+ }
+ developer {
+ id = 'akien-mga'
+ name = 'RĂ©mi Verschelde'
+ email = 'rverschelde@gmail.com'
+ }
+ // Add all other devs here...
+ }
+
+ // Version control info - if you're using GitHub, follow the
+ // format as seen here
+ scm {
+ connection = 'scm:git:github.com/godotengine/godot.git'
+ developerConnection = 'scm:git:ssh://github.com/godotengine/godot.git'
+ url = 'https://github.com/godotengine/godot/tree/master'
+ }
+ }
+ }
+ }
+ }
+}
+
+signing {
+ useInMemoryPgpKeys(
+ rootProject.ext["signing.keyId"],
+ rootProject.ext["signing.key"],
+ rootProject.ext["signing.password"],
+ )
+ sign publishing.publications
+}
diff --git a/platform/android/java/scripts/publish-root.gradle b/platform/android/java/scripts/publish-root.gradle
new file mode 100644
index 0000000000..ae88487c34
--- /dev/null
+++ b/platform/android/java/scripts/publish-root.gradle
@@ -0,0 +1,39 @@
+// Create variables with empty default values
+ext["signing.keyId"] = ''
+ext["signing.password"] = ''
+ext["signing.key"] = ''
+ext["ossrhGroupId"] = ''
+ext["ossrhUsername"] = ''
+ext["ossrhPassword"] = ''
+ext["sonatypeStagingProfileId"] = ''
+
+File secretPropsFile = project.rootProject.file('local.properties')
+if (secretPropsFile.exists()) {
+ // Read local.properties file first if it exists
+ Properties p = new Properties()
+ new FileInputStream(secretPropsFile).withCloseable { is -> p.load(is) }
+ p.each { name, value -> ext[name] = value }
+} else {
+ // Use system environment variables
+ ext["ossrhGroupId"] = System.getenv('OSSRH_GROUP_ID')
+ ext["ossrhUsername"] = System.getenv('OSSRH_USERNAME')
+ ext["ossrhPassword"] = System.getenv('OSSRH_PASSWORD')
+ ext["sonatypeStagingProfileId"] = System.getenv('SONATYPE_STAGING_PROFILE_ID')
+ ext["signing.keyId"] = System.getenv('SIGNING_KEY_ID')
+ ext["signing.password"] = System.getenv('SIGNING_PASSWORD')
+ ext["signing.key"] = System.getenv('SIGNING_KEY')
+}
+
+// Set up Sonatype repository
+nexusPublishing {
+ repositories {
+ sonatype {
+ stagingProfileId = sonatypeStagingProfileId
+ username = ossrhUsername
+ password = ossrhPassword
+ nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/"))
+ snapshotRepositoryUrl.set(uri("https://s01.oss.sonatype.org/content/repositories/snapshots/"))
+ }
+ }
+}
+
diff --git a/platform/iphone/export/export_plugin.cpp b/platform/iphone/export/export_plugin.cpp
index 26c5acb13e..ac5886e620 100644
--- a/platform/iphone/export/export_plugin.cpp
+++ b/platform/iphone/export/export_plugin.cpp
@@ -1440,7 +1440,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
}
String pack_path = dest_dir + binary_name + ".pck";
Vector<SharedObject> libraries;
- Error err = save_pack(p_preset, pack_path, &libraries);
+ Error err = save_pack(p_preset, p_debug, pack_path, &libraries);
if (err) {
return err;
}
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index 2caf369354..a38040922d 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -34,7 +34,7 @@
#include "drivers/gles3/rasterizer_gles3.h"
#endif
#include "platform/javascript/os_javascript.h"
-#include "servers/rendering/rasterizer_dummy.h"
+#include "servers/rendering/dummy/rasterizer_dummy.h"
#include <emscripten.h>
#include <png.h>
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index e7855acf60..4448acccc2 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -440,7 +440,7 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
// Export pck and shared objects
Vector<SharedObject> shared_objects;
String pck_path = base_path + ".pck";
- Error error = save_pack(p_preset, pck_path, &shared_objects);
+ Error error = save_pack(p_preset, p_debug, pck_path, &shared_objects);
if (error != OK) {
EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path);
return error;
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index f05d2faa11..8aa6c47c15 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/export/export.cpp
@@ -30,15 +30,10 @@
#include "export.h"
-#include "core/io/file_access.h"
-#include "editor/editor_export.h"
-#include "platform/linuxbsd/logo.gen.h"
-#include "scene/resources/texture.h"
-
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
+#include "export_plugin.h"
void register_linuxbsd_exporter() {
- Ref<EditorExportPlatformPC> platform;
+ Ref<EditorExportPlatformLinuxBSD> platform;
platform.instantiate();
Ref<Image> img = memnew(Image(_linuxbsd_logo));
@@ -47,7 +42,7 @@ void register_linuxbsd_exporter() {
logo->create_from_image(img);
platform->set_logo(logo);
platform->set_name("Linux/X11");
- platform->set_extension("x86");
+ platform->set_extension("x86_32");
platform->set_extension("x86_64", "binary_format/64_bits");
platform->set_release_32("linux_x11_32_release");
platform->set_debug_32("linux_x11_32_debug");
@@ -55,112 +50,6 @@ void register_linuxbsd_exporter() {
platform->set_debug_64("linux_x11_64_debug");
platform->set_os_name("LinuxBSD");
platform->set_chmod_flags(0755);
- platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
EditorExport::get_singleton()->add_export_platform(platform);
}
-
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
- // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
-
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
- if (!f) {
- return ERR_CANT_OPEN;
- }
-
- // Read and check ELF magic number
- {
- uint32_t magic = f->get_32();
- if (magic != 0x464c457f) { // 0x7F + "ELF"
- f->close();
- return ERR_FILE_CORRUPT;
- }
- }
-
- // Read program architecture bits from class field
-
- int bits = f->get_8() * 32;
-
- if (bits == 32 && p_embedded_size >= 0x100000000) {
- f->close();
- ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
- }
-
- // Get info about the section header table
-
- int64_t section_table_pos;
- int64_t section_header_size;
- if (bits == 32) {
- section_header_size = 40;
- f->seek(0x20);
- section_table_pos = f->get_32();
- f->seek(0x30);
- } else { // 64
- section_header_size = 64;
- f->seek(0x28);
- section_table_pos = f->get_64();
- f->seek(0x3c);
- }
- int num_sections = f->get_16();
- int string_section_idx = f->get_16();
-
- // Load the strings table
- uint8_t *strings;
- {
- // Jump to the strings section header
- f->seek(section_table_pos + string_section_idx * section_header_size);
-
- // Read strings data size and offset
- int64_t string_data_pos;
- int64_t string_data_size;
- if (bits == 32) {
- f->seek(f->get_position() + 0x10);
- string_data_pos = f->get_32();
- string_data_size = f->get_32();
- } else { // 64
- f->seek(f->get_position() + 0x18);
- string_data_pos = f->get_64();
- string_data_size = f->get_64();
- }
-
- // Read strings data
- f->seek(string_data_pos);
- strings = (uint8_t *)memalloc(string_data_size);
- if (!strings) {
- f->close();
- return ERR_OUT_OF_MEMORY;
- }
- f->get_buffer(strings, string_data_size);
- }
-
- // Search for the "pck" section
-
- bool found = false;
- for (int i = 0; i < num_sections; ++i) {
- int64_t section_header_pos = section_table_pos + i * section_header_size;
- f->seek(section_header_pos);
-
- uint32_t name_offset = f->get_32();
- if (strcmp((char *)strings + name_offset, "pck") == 0) {
- // "pck" section found, let's patch!
-
- if (bits == 32) {
- f->seek(section_header_pos + 0x10);
- f->store_32(p_embedded_start);
- f->store_32(p_embedded_size);
- } else { // 64
- f->seek(section_header_pos + 0x18);
- f->store_64(p_embedded_start);
- f->store_64(p_embedded_size);
- }
-
- found = true;
- break;
- }
- }
-
- memfree(strings);
- f->close();
-
- return found ? OK : ERR_FILE_CORRUPT;
-}
diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp
new file mode 100644
index 0000000000..08fc9c0452
--- /dev/null
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -0,0 +1,200 @@
+/*************************************************************************/
+/* export_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "export_plugin.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_node.h"
+
+Error EditorExportPlatformLinuxBSD::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);
+
+ f->store_line("#!/bin/sh");
+ f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'");
+ f->store_line("base_path=\"$(dirname \"$(realpath \"$0\")\")\"");
+ f->store_line("\"$base_path/" + p_pkg_name + "\" \"$@\"");
+
+ return OK;
+}
+
+Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
+
+ if (err != OK) {
+ return err;
+ }
+
+ String app_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ app_name = "Unnamed";
+ }
+ app_name = OS::get_singleton()->get_safe_dir_name(app_name);
+
+ // Save console script.
+ if (err == OK) {
+ int con_scr = p_preset->get("debug/export_console_script");
+ if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
+ String scr_path = p_path.get_basename() + ".sh";
+ err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
+ FileAccess::set_unix_permissions(scr_path, 0755);
+ }
+ }
+
+ return err;
+}
+
+void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, const String &p_feature_key) {
+ extensions[p_feature_key] = p_extension;
+}
+
+List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ for (const KeyValue<String, String> &E : extensions) {
+ if (p_preset->get(E.key)) {
+ list.push_back(extensions[E.key]);
+ return list;
+ }
+ }
+
+ if (extensions.has("default")) {
+ list.push_back(extensions["default"]);
+ return list;
+ }
+
+ return list;
+}
+
+Error EditorExportPlatformLinuxBSD::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+ // Patch the header of the "pck" section in the ELF file so that it corresponds to the embedded data
+
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
+ if (!f) {
+ return ERR_CANT_OPEN;
+ }
+
+ // Read and check ELF magic number
+ {
+ uint32_t magic = f->get_32();
+ if (magic != 0x464c457f) { // 0x7F + "ELF"
+ f->close();
+ return ERR_FILE_CORRUPT;
+ }
+ }
+
+ // Read program architecture bits from class field
+
+ int bits = f->get_8() * 32;
+
+ if (bits == 32 && p_embedded_size >= 0x100000000) {
+ f->close();
+ ERR_FAIL_V_MSG(ERR_INVALID_DATA, "32-bit executables cannot have embedded data >= 4 GiB.");
+ }
+
+ // Get info about the section header table
+
+ int64_t section_table_pos;
+ int64_t section_header_size;
+ if (bits == 32) {
+ section_header_size = 40;
+ f->seek(0x20);
+ section_table_pos = f->get_32();
+ f->seek(0x30);
+ } else { // 64
+ section_header_size = 64;
+ f->seek(0x28);
+ section_table_pos = f->get_64();
+ f->seek(0x3c);
+ }
+ int num_sections = f->get_16();
+ int string_section_idx = f->get_16();
+
+ // Load the strings table
+ uint8_t *strings;
+ {
+ // Jump to the strings section header
+ f->seek(section_table_pos + string_section_idx * section_header_size);
+
+ // Read strings data size and offset
+ int64_t string_data_pos;
+ int64_t string_data_size;
+ if (bits == 32) {
+ f->seek(f->get_position() + 0x10);
+ string_data_pos = f->get_32();
+ string_data_size = f->get_32();
+ } else { // 64
+ f->seek(f->get_position() + 0x18);
+ string_data_pos = f->get_64();
+ string_data_size = f->get_64();
+ }
+
+ // Read strings data
+ f->seek(string_data_pos);
+ strings = (uint8_t *)memalloc(string_data_size);
+ if (!strings) {
+ f->close();
+ return ERR_OUT_OF_MEMORY;
+ }
+ f->get_buffer(strings, string_data_size);
+ }
+
+ // Search for the "pck" section
+
+ bool found = false;
+ for (int i = 0; i < num_sections; ++i) {
+ int64_t section_header_pos = section_table_pos + i * section_header_size;
+ f->seek(section_header_pos);
+
+ uint32_t name_offset = f->get_32();
+ if (strcmp((char *)strings + name_offset, "pck") == 0) {
+ // "pck" section found, let's patch!
+
+ if (bits == 32) {
+ f->seek(section_header_pos + 0x10);
+ f->store_32(p_embedded_start);
+ f->store_32(p_embedded_size);
+ } else { // 64
+ f->seek(section_header_pos + 0x18);
+ f->store_64(p_embedded_start);
+ f->store_64(p_embedded_size);
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ memfree(strings);
+ f->close();
+
+ return found ? OK : ERR_FILE_CORRUPT;
+}
diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h
new file mode 100644
index 0000000000..593916e586
--- /dev/null
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* export_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef LINUXBSD_EXPORT_PLUGIN_H
+#define LINUXBSD_EXPORT_PLUGIN_H
+
+#include "core/io/file_access.h"
+#include "editor/editor_export.h"
+#include "editor/editor_settings.h"
+#include "platform/linuxbsd/logo.gen.h"
+#include "scene/resources/texture.h"
+
+class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC {
+ Map<String, String> extensions;
+ Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
+
+public:
+ void set_extension(const String &p_extension, const String &p_feature_key = "default");
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
+ virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
+};
+
+#endif
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index cc9ac162ea..d9a0d2ce17 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -186,6 +186,7 @@ private:
void _process_key_events();
void _update_keyboard_layouts();
static void _keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info);
+ NSImage *_convert_to_nsimg(Ref<Image> &p_image) const;
static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil);
@@ -217,24 +218,46 @@ public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
- virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant()) override;
- virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag = Variant()) override;
- virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) override;
- virtual void global_menu_add_separator(const String &p_menu_root) override;
+ virtual void global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual void global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override;
+ virtual void global_menu_add_separator(const String &p_menu_root, int p_index = -1) override;
+
+ virtual int global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const override;
+ virtual int global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const override;
virtual bool global_menu_is_item_checked(const String &p_menu_root, int p_idx) const override;
virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const override;
- virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) override;
- virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) override;
- virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) override;
- virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) override;
+ virtual bool global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const override;
+ virtual Callable global_menu_get_item_callback(const String &p_menu_root, int p_idx) const override;
+ virtual Variant global_menu_get_item_tag(const String &p_menu_root, int p_idx) const override;
+ virtual String global_menu_get_item_text(const String &p_menu_root, int p_idx) const override;
+ virtual String global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const override;
+ virtual Key global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const override;
+ virtual bool global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const override;
+ virtual String global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const override;
+ virtual int global_menu_get_item_state(const String &p_menu_root, int p_idx) const override;
+ virtual int global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const override;
+ virtual Ref<Texture2D> global_menu_get_item_icon(const String &p_menu_root, int p_idx) const override;
virtual void global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) override;
virtual void global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override;
+ virtual void global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) override;
virtual void global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) override;
virtual void global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) override;
virtual void global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) override;
virtual void global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) override;
+ virtual void global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) override;
+ virtual void global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) override;
+ virtual void global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) override;
+ virtual void global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) override;
+ virtual void global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) override;
+ virtual void global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) override;
virtual int global_menu_get_item_count(const String &p_menu_root) const override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 89ca6e50ec..9e32cab5ed 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -91,6 +91,7 @@ NSMenu *DisplayServerOSX::_get_menu_root(const String &p_menu_root) {
// Submenu.
if (!submenu.has(p_menu_root)) {
NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]];
+ [n_menu setAutoenablesItems:NO];
submenu[p_menu_root] = n_menu;
}
menu = submenu[p_menu_root];
@@ -472,6 +473,40 @@ void DisplayServerOSX::_keyboard_layout_changed(CFNotificationCenterRef center,
}
}
+NSImage *DisplayServerOSX::_convert_to_nsimg(Ref<Image> &p_image) const {
+ p_image->convert(Image::FORMAT_RGBA8);
+ NSBitmapImageRep *imgrep = [[NSBitmapImageRep alloc]
+ initWithBitmapDataPlanes:NULL
+ pixelsWide:p_image->get_width()
+ pixelsHigh:p_image->get_height()
+ bitsPerSample:8
+ samplesPerPixel:4
+ hasAlpha:YES
+ isPlanar:NO
+ colorSpaceName:NSDeviceRGBColorSpace
+ bytesPerRow:int(p_image->get_width()) * 4
+ bitsPerPixel:32];
+ ERR_FAIL_COND_V(imgrep == nil, nil);
+ uint8_t *pixels = [imgrep bitmapData];
+
+ int len = p_image->get_width() * p_image->get_height();
+ const uint8_t *r = p_image->get_data().ptr();
+
+ /* Premultiply the alpha channel */
+ for (int i = 0; i < len; i++) {
+ uint8_t alpha = r[i * 4 + 3];
+ pixels[i * 4 + 0] = (uint8_t)(((uint16_t)r[i * 4 + 0] * alpha) / 255);
+ pixels[i * 4 + 1] = (uint8_t)(((uint16_t)r[i * 4 + 1] * alpha) / 255);
+ pixels[i * 4 + 2] = (uint8_t)(((uint16_t)r[i * 4 + 2] * alpha) / 255);
+ pixels[i * 4 + 3] = alpha;
+ }
+
+ NSImage *nsimg = [[NSImage alloc] initWithSize:NSMakeSize(p_image->get_width(), p_image->get_height())];
+ ERR_FAIL_COND_V(nsimg == nil, nil);
+ [nsimg addRepresentation:imgrep];
+ return nsimg;
+}
+
NSCursor *DisplayServerOSX::_cursor_from_selector(SEL p_selector, SEL p_fallback) {
if ([NSCursor respondsToSelector:p_selector]) {
id object = [NSCursor performSelector:p_selector];
@@ -498,7 +533,14 @@ void DisplayServerOSX::menu_callback(id p_sender) {
GodotMenuItem *value = [p_sender representedObject];
if (value) {
- if (value->checkable) {
+ if (value->max_states > 0) {
+ value->state++;
+ if (value->state >= value->max_states) {
+ value->state = 0;
+ }
+ }
+
+ if (value->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
if ([p_sender state] == NSControlStateValueOff) {
[p_sender setState:NSControlStateValueOn];
} else {
@@ -671,35 +713,195 @@ String DisplayServerOSX::get_name() const {
return "OSX";
}
-void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+void DisplayServerOSX::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable_type = CHECKABLE_TYPE_NONE;
+ obj->max_states = 0;
+ obj->state = 0;
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
+ obj->max_states = 0;
+ obj->state = 0;
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable_type = CHECKABLE_TYPE_NONE;
+ obj->max_states = 0;
+ obj->state = 0;
+ if (p_icon.is_valid()) {
+ obj->img = p_icon->get_image();
+ obj->img = obj->img->duplicate();
+ if (obj->img->is_compressed()) {
+ obj->img->decompress();
+ }
+ obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS);
+ [menu_item setImage:_convert_to_nsimg(obj->img)];
+ }
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
+ obj->max_states = 0;
+ obj->state = 0;
+ if (p_icon.is_valid()) {
+ obj->img = p_icon->get_image();
+ obj->img = obj->img->duplicate();
+ if (obj->img->is_compressed()) {
+ obj->img->decompress();
+ }
+ obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS);
+ [menu_item setImage:_convert_to_nsimg(obj->img)];
+ }
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ GodotMenuItem *obj = [[GodotMenuItem alloc] init];
+ obj->callback = p_callback;
+ obj->meta = p_tag;
+ obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
+ obj->max_states = 0;
+ obj->state = 0;
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
+ [menu_item setRepresentedObject:obj];
+ }
+}
+
+void DisplayServerOSX::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
- obj->checkable = false;
+ obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
+ obj->max_states = 0;
+ obj->state = 0;
+ if (p_icon.is_valid()) {
+ obj->img = p_icon->get_image();
+ obj->img = obj->img->duplicate();
+ if (obj->img->is_compressed()) {
+ obj->img->decompress();
+ }
+ obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS);
+ [menu_item setImage:_convert_to_nsimg(obj->img)];
+ }
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
}
-void DisplayServerOSX::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Variant &p_tag) {
+void DisplayServerOSX::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
obj->meta = p_tag;
- obj->checkable = true;
+ obj->checkable_type = CHECKABLE_TYPE_NONE;
+ obj->max_states = p_max_states;
+ obj->state = p_default_state;
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_accel)];
[menu_item setRepresentedObject:obj];
}
}
-void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu) {
+void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
@@ -713,18 +915,58 @@ void DisplayServerOSX::global_menu_add_submenu_item(const String &p_menu_root, c
ERR_PRINT("Can't set submenu to menu that is already a submenu of some other menu!");
return;
}
- NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""];
+ NSMenuItem *menu_item;
+ if (p_index != -1) {
+ menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
+ } else {
+ menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@""];
+ }
+ [sub_menu setTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()]];
[menu setSubmenu:sub_menu forItem:menu_item];
}
}
-void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root) {
+void DisplayServerOSX::global_menu_add_separator(const String &p_menu_root, int p_index) {
_THREAD_SAFE_METHOD_
NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
- [menu addItem:[NSMenuItem separatorItem]];
+ if (p_index != -1) {
+ [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index];
+ } else {
+ [menu addItem:[NSMenuItem separatorItem]];
+ }
+ }
+}
+
+int DisplayServerOSX::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
}
+
+ return -1;
+}
+
+int DisplayServerOSX::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ for (NSInteger i = 0; i < [menu numberOfItems]; i++) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:i];
+ if (menu_item) {
+ const GodotMenuItem *obj = [menu_item representedObject];
+ if (obj && obj->meta == p_tag) {
+ return i;
+ }
+ }
+ }
+ }
+
+ return -1;
}
bool DisplayServerOSX::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const {
@@ -749,14 +991,30 @@ bool DisplayServerOSX::global_menu_is_item_checkable(const String &p_menu_root,
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
if (obj) {
- return obj->checkable;
+ return obj->checkable_type == CHECKABLE_TYPE_CHECK_BOX;
+ }
+ }
+ }
+ return false;
+}
+
+bool DisplayServerOSX::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->checkable_type == CHECKABLE_TYPE_RADIO_BUTTON;
}
}
}
return false;
}
-Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) {
+Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
const NSMenu *menu = _get_menu_root(p_menu_root);
@@ -772,7 +1030,7 @@ Callable DisplayServerOSX::global_menu_get_item_callback(const String &p_menu_ro
return Callable();
}
-Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) {
+Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
const NSMenu *menu = _get_menu_root(p_menu_root);
@@ -788,22 +1046,20 @@ Variant DisplayServerOSX::global_menu_get_item_tag(const String &p_menu_root, in
return Variant();
}
-String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) {
+String DisplayServerOSX::global_menu_get_item_text(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) {
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
- String ret;
- ret.parse_utf8([[menu_item title] UTF8String]);
- return ret;
+ return String::utf8([[menu_item title] UTF8String]);
}
}
return String();
}
-String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) {
+String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
const NSMenu *menu = _get_menu_root(p_menu_root);
@@ -823,6 +1079,116 @@ String DisplayServerOSX::global_menu_get_item_submenu(const String &p_menu_root,
return String();
}
+Key DisplayServerOSX::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ String ret = String::utf8([[menu_item keyEquivalent] UTF8String]);
+ Key keycode = find_keycode(ret);
+ NSUInteger mask = [menu_item keyEquivalentModifierMask];
+ if (mask & NSEventModifierFlagControl) {
+ keycode |= KeyModifierMask::CTRL;
+ }
+ if (mask & NSEventModifierFlagOption) {
+ keycode |= KeyModifierMask::ALT;
+ }
+ if (mask & NSEventModifierFlagShift) {
+ keycode |= KeyModifierMask::SHIFT;
+ }
+ if (mask & NSEventModifierFlagCommand) {
+ keycode |= KeyModifierMask::META;
+ }
+ if (mask & NSEventModifierFlagNumericPad) {
+ keycode |= KeyModifierMask::KPAD;
+ }
+ return keycode;
+ }
+ }
+ return Key::NONE;
+}
+
+bool DisplayServerOSX::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ return ![menu_item isEnabled];
+ }
+ }
+ return false;
+}
+
+String DisplayServerOSX::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ return String::utf8([[menu_item toolTip] UTF8String]);
+ }
+ }
+ return String();
+}
+
+int DisplayServerOSX::global_menu_get_item_state(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->state;
+ }
+ }
+ }
+ return 0;
+}
+
+int DisplayServerOSX::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->max_states;
+ }
+ }
+ }
+ return 0;
+}
+
+Ref<Texture2D> DisplayServerOSX::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ if (obj->img.is_valid()) {
+ Ref<ImageTexture> txt;
+ txt.instantiate();
+ txt->create_from_image(obj->img);
+ return txt;
+ }
+ }
+ }
+ }
+ return Ref<Texture2D>();
+}
+
void DisplayServerOSX::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) {
_THREAD_SAFE_METHOD_
@@ -853,7 +1219,23 @@ void DisplayServerOSX::global_menu_set_item_checkable(const String &p_menu_root,
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- obj->checkable = p_checkable;
+ obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE;
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_RADIO_BUTTON : CHECKABLE_TYPE_NONE;
}
}
}
@@ -929,6 +1311,116 @@ void DisplayServerOSX::global_menu_set_item_submenu(const String &p_menu_root, i
}
}
+void DisplayServerOSX::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu_item setKeyEquivalentModifierMask:KeyMappingOSX::keycode_get_native_mask(p_keycode)];
+ String keycode = KeyMappingOSX::keycode_get_native_string(p_keycode & KeyModifierMask::CODE_MASK);
+ [menu_item setKeyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu_item setEnabled:(!p_disabled)];
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ [menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]];
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ obj->state = p_state;
+ }
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ obj->max_states = p_max_states;
+ }
+ }
+ }
+}
+
+void DisplayServerOSX::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ if ((menu == [NSApp mainMenu]) && (p_idx == 0)) { // Do not edit Apple menu.
+ return;
+ }
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (p_icon.is_valid()) {
+ obj->img = p_icon->get_image();
+ obj->img = obj->img->duplicate();
+ if (obj->img->is_compressed()) {
+ obj->img->decompress();
+ }
+ obj->img->resize(16, 16, Image::INTERPOLATE_LANCZOS);
+ [menu_item setImage:_convert_to_nsimg(obj->img)];
+ } else {
+ obj->img = Ref<Image>();
+ [menu_item setImage:nil];
+ }
+ }
+ }
+}
+
int DisplayServerOSX::global_menu_get_item_count(const String &p_menu_root) const {
_THREAD_SAFE_METHOD_
@@ -2628,11 +3120,13 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
// Setup Dock menu.
dock_menu = [[NSMenu alloc] initWithTitle:@"_dock"];
+ [dock_menu setAutoenablesItems:NO];
// Setup Apple menu.
apple_menu = [[NSMenu alloc] initWithTitle:@""];
title = [NSString stringWithFormat:NSLocalizedString(@"About %@", nil), nsappname];
[apple_menu addItemWithTitle:title action:@selector(showAbout:) keyEquivalent:@""];
+ [apple_menu setAutoenablesItems:NO];
[apple_menu addItem:[NSMenuItem separatorItem]];
@@ -2660,6 +3154,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode
NSMenu *main_menu = [NSApp mainMenu];
menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[main_menu setSubmenu:apple_menu forItem:menu_item];
+ [main_menu setAutoenablesItems:NO];
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback
diff --git a/platform/osx/export/export_plugin.cpp b/platform/osx/export/export_plugin.cpp
index 0f4477d312..4f06342fac 100644
--- a/platform/osx/export/export_plugin.cpp
+++ b/platform/osx/export/export_plugin.cpp
@@ -72,6 +72,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "debug/export_console_script", PROPERTY_HINT_ENUM, "No,Debug Only,Debug and Release"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
@@ -458,7 +459,7 @@ Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset
return OK;
}
-Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path) {
+Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn) {
bool force_builtin_codesign = EditorSettings::get_singleton()->get("export/macos/force_builtin_codesign");
bool ad_hoc = (p_preset->get("codesign/identity") == "" || p_preset->get("codesign/identity") == "-");
@@ -467,10 +468,10 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
#ifdef MODULE_REGEX_ENABLED
#ifdef OSX_ENABLED
- if (p_preset->get("codesign/timestamp")) {
+ if (p_preset->get("codesign/timestamp") && p_warn) {
WARN_PRINT("Timestamping is not compatible with ad-hoc signature, and was disabled!");
}
- if (p_preset->get("codesign/hardened_runtime")) {
+ if (p_preset->get("codesign/hardened_runtime") && p_warn) {
WARN_PRINT("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!");
}
#endif
@@ -490,14 +491,18 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
List<String> args;
if (p_preset->get("codesign/timestamp")) {
if (ad_hoc) {
- WARN_PRINT("Timestamping is not compatible with ad-hoc signature, and was disabled!");
+ if (p_warn) {
+ WARN_PRINT("Timestamping is not compatible with ad-hoc signature, and was disabled!");
+ }
} else {
args.push_back("--timestamp");
}
}
if (p_preset->get("codesign/hardened_runtime")) {
if (ad_hoc) {
- WARN_PRINT("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!");
+ if (p_warn) {
+ WARN_PRINT("Hardened Runtime is not compatible with ad-hoc signature, and was disabled!");
+ }
} else {
args.push_back("--options");
args.push_back("runtime");
@@ -577,7 +582,7 @@ Error EditorExportPlatformOSX::_code_sign_directory(const Ref<EditorExportPreset
}
if (extensions_to_sign.find(current_file.get_extension()) > -1) {
- Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path) };
+ Error code_sign_error{ _code_sign(p_preset, current_file_path, p_ent_path, false) };
if (code_sign_error != OK) {
return code_sign_error;
}
@@ -621,7 +626,7 @@ Error EditorExportPlatformOSX::_copy_and_sign_files(DirAccessRef &dir_access, co
// If it is a directory, find and sign all dynamic libraries.
err = _code_sign_directory(p_preset, p_in_app_path, p_ent_path, p_should_error_on_non_code_sign);
} else {
- err = _code_sign(p_preset, p_in_app_path, p_ent_path);
+ err = _code_sign(p_preset, p_in_app_path, p_ent_path, false);
}
}
return err;
@@ -677,6 +682,19 @@ Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const Strin
return OK;
}
+Error EditorExportPlatformOSX::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);
+
+ f->store_line("#!/bin/sh");
+ f->store_line("echo -ne '\\033c\\033]0;" + p_app_name + "\\a'");
+ f->store_line("function realpath() { python -c \"import os,sys; print(os.path.realpath(sys.argv[1]))\" \"$0\"; }");
+ f->store_line("base_path=\"$(dirname \"$(realpath \"$0\")\")\"");
+ f->store_line("\"$base_path/" + p_pkg_name + "\" \"$@\"");
+
+ return OK;
+}
+
Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags);
@@ -743,22 +761,30 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Create our application bundle.
String tmp_app_dir_name = pkg_name + ".app";
+ String tmp_base_path_name;
String tmp_app_path_name;
+ String scr_path;
if (export_format == "app") {
+ tmp_base_path_name = p_path.get_base_dir();
tmp_app_path_name = p_path;
+ scr_path = p_path.get_basename() + ".command";
} else {
- tmp_app_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
+ tmp_base_path_name = EditorPaths::get_singleton()->get_cache_dir().plus_file(pkg_name);
+ tmp_app_path_name = tmp_base_path_name.plus_file(tmp_app_dir_name);
+ scr_path = tmp_base_path_name.plus_file(pkg_name + ".command");
}
+
print_verbose("Exporting to " + tmp_app_path_name);
Error err = OK;
- DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name);
+ DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_base_path_name);
if (!tmp_app_dir) {
err = ERR_CANT_CREATE;
}
- if (DirAccess::exists(tmp_app_dir_name)) {
+ DirAccess::remove_file_or_error(scr_path);
+ if (DirAccess::exists(tmp_app_path_name)) {
if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
tmp_app_dir->erase_contents_recursive();
}
@@ -1039,6 +1065,15 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
err = ERR_FILE_NOT_FOUND;
}
+ // Save console script.
+ if (err == OK) {
+ int con_scr = p_preset->get("debug/export_console_script");
+ if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
+ err = _export_debug_script(p_preset, pkg_name, tmp_app_path_name.get_file() + "/Contents/MacOS/" + pkg_name, scr_path);
+ FileAccess::set_unix_permissions(scr_path, 0755);
+ }
+ }
+
if (err == OK) {
if (ep.step(TTR("Making PKG"), 1)) {
return ERR_SKIP;
@@ -1046,7 +1081,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
String pack_path = tmp_app_path_name + "/Contents/Resources/" + pkg_name + ".pck";
Vector<SharedObject> shared_objects;
- err = save_pack(p_preset, pack_path, &shared_objects);
+ err = save_pack(p_preset, p_debug, pack_path, &shared_objects);
// See if we can code sign our new package.
bool sign_enabled = p_preset->get("codesign/enable");
@@ -1213,7 +1248,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
String hlp_path = helpers[i];
err = da->copy(hlp_path, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file());
if (err == OK && sign_enabled) {
- err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path);
+ err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), hlp_ent_path, false);
}
FileAccess::set_unix_permissions(tmp_app_path_name + "/Contents/Helpers/" + hlp_path.get_file(), 0755);
}
@@ -1238,8 +1273,13 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
for (int i = 0; i < shared_objects.size(); i++) {
String src_path = ProjectSettings::get_singleton()->globalize_path(shared_objects[i].path);
- String path_in_app{ tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file() };
- err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
+ if (shared_objects[i].target.is_empty()) {
+ String path_in_app = tmp_app_path_name + "/Contents/Frameworks/" + src_path.get_file();
+ err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, true);
+ } else {
+ String path_in_app = tmp_app_path_name.plus_file(shared_objects[i].target).plus_file(src_path.get_file());
+ err = _copy_and_sign_files(da, src_path, path_in_app, sign_enabled, p_preset, ent_path, false);
+ }
if (err != OK) {
break;
}
@@ -1257,7 +1297,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (sign_enabled) {
for (int i = 0; i < dylibs_found.size(); i++) {
if (err == OK) {
- err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path);
+ err = _code_sign(p_preset, tmp_app_path_name + "/" + dylibs_found[i], ent_path, false);
}
}
}
@@ -1275,14 +1315,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
if (ep.step(TTR("Making DMG"), 3)) {
return ERR_SKIP;
}
- err = _create_dmg(p_path, pkg_name, tmp_app_path_name);
+ err = _create_dmg(p_path, pkg_name, tmp_base_path_name);
}
// Sign DMG.
if (err == OK && sign_enabled && !ad_hoc) {
if (ep.step(TTR("Code signing DMG"), 3)) {
return ERR_SKIP;
}
- err = _code_sign(p_preset, p_path, ent_path);
+ err = _code_sign(p_preset, p_path, ent_path, false);
}
} else if (export_format == "zip") {
// Create ZIP.
@@ -1298,7 +1338,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
zlib_filefunc_def io_dst = zipio_create_io_from_file(&dst_f);
zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io_dst);
- _zip_folder_recursive(zip, EditorPaths::get_singleton()->get_cache_dir(), pkg_name + ".app", pkg_name);
+ _zip_folder_recursive(zip, tmp_base_path_name, "", pkg_name);
zipClose(zip, nullptr);
}
@@ -1326,10 +1366,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
tmp_app_dir->remove(ent_path);
}
if (export_format != "app") {
- if (tmp_app_dir->change_dir(tmp_app_path_name) == OK) {
+ if (tmp_app_dir->change_dir(tmp_base_path_name) == OK) {
tmp_app_dir->erase_contents_recursive();
tmp_app_dir->change_dir("..");
- tmp_app_dir->remove(tmp_app_dir_name);
+ tmp_app_dir->remove(pkg_name);
}
}
}
@@ -1338,7 +1378,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name) {
- String dir = p_root_path.plus_file(p_folder);
+ String dir = p_folder.is_empty() ? p_root_path : p_root_path.plus_file(p_folder);
DirAccessRef da = DirAccess::open(dir);
da->list_dir_begin();
@@ -1392,7 +1432,7 @@ void EditorExportPlatformOSX::_zip_folder_recursive(zipFile &p_zip, const String
} else if (da->current_is_dir()) {
_zip_folder_recursive(p_zip, p_root_path, p_folder.plus_file(f), p_pkg_name);
} else {
- bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers");
+ bool is_executable = (p_folder.ends_with("MacOS") && (f == p_pkg_name)) || p_folder.ends_with("Helpers") || f.ends_with(".command");
OS::Time time = OS::get_singleton()->get_time();
OS::Date date = OS::get_singleton()->get_date();
diff --git a/platform/osx/export/export_plugin.h b/platform/osx/export/export_plugin.h
index b85e9d662c..b3edfb7f90 100644
--- a/platform/osx/export/export_plugin.h
+++ b/platform/osx/export/export_plugin.h
@@ -56,7 +56,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
- Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path);
+ Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_warn = true);
Error _code_sign_directory(const Ref<EditorExportPreset> &p_preset, const String &p_path, const String &p_ent_path, bool p_should_error_on_non_code = true);
Error _copy_and_sign_files(DirAccessRef &dir_access, const String &p_src_path, const String &p_in_app_path,
bool p_sign_enabled, const Ref<EditorExportPreset> &p_preset, const String &p_ent_path,
@@ -66,6 +66,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
const String &p_ent_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
+ Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
bool use_codesign() const { return true; }
#ifdef OSX_ENABLED
diff --git a/platform/osx/godot_menu_item.h b/platform/osx/godot_menu_item.h
index 50c4709c18..2c12897f10 100644
--- a/platform/osx/godot_menu_item.h
+++ b/platform/osx/godot_menu_item.h
@@ -36,12 +36,21 @@
#import <AppKit/AppKit.h>
#import <Foundation/Foundation.h>
+enum GlobalMenuCheckType {
+ CHECKABLE_TYPE_NONE,
+ CHECKABLE_TYPE_CHECK_BOX,
+ CHECKABLE_TYPE_RADIO_BUTTON,
+};
+
@interface GodotMenuItem : NSObject {
@public
Callable callback;
Variant meta;
int id;
- bool checkable;
+ GlobalMenuCheckType checkable_type;
+ int max_states;
+ int state;
+ Ref<Image> img;
}
@end
diff --git a/platform/uwp/export/export_plugin.cpp b/platform/uwp/export/export_plugin.cpp
index a76ff042b2..230e5c749c 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -416,7 +416,7 @@ Error EditorExportPlatformUWP::export_project(const Ref<EditorExportPreset> &p_p
EditorNode::progress_add_task("project_files", "Project Files", 100);
packager.set_progress_task("project_files");
- err = export_project_files(p_preset, save_appx_file, &packager);
+ err = export_project_files(p_preset, p_debug, save_appx_file, &packager);
EditorNode::progress_end_task("project_files");
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 27b4a2018f..d243d4c05d 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1917,16 +1917,14 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- // TODO disabling for now
- //context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
#endif
}
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- //TODO disabling for now
- //return context_vulkan->get_vsync_mode(p_window);
+ return context_vulkan->get_vsync_mode(p_window);
#endif
return DisplayServer::VSYNC_ENABLED;
}
@@ -2122,7 +2120,6 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
case WM_NCRBUTTONDOWN:
case WM_NCMBUTTONDOWN:
case WM_LBUTTONDOWN:
- case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: {
MOUSEHOOKSTRUCT *ms = (MOUSEHOOKSTRUCT *)lParam;
Point2i pos = Point2i(ms->pt.x, ms->pt.y);
@@ -3598,12 +3595,11 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
return;
}
- //gl_manager->set_use_vsync(current_videomode.use_vsync);
RasterizerGLES3::make_current();
}
#endif
- HHOOK mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
+ mouse_monitor = SetWindowsHookEx(WH_MOUSE, ::MouseProc, nullptr, GetCurrentThreadId());
Point2i window_position(
(screen_get_size(0).width - p_resolution.width) / 2,
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 17a24c08bf..37fdf93ecf 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -32,8 +32,6 @@
#include "export_plugin.h"
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size);
-
void register_windows_exporter() {
EDITOR_DEF("export/windows/rcedit", "");
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe"));
@@ -57,84 +55,11 @@ void register_windows_exporter() {
logo->create_from_image(img);
platform->set_logo(logo);
platform->set_name("Windows Desktop");
- platform->set_extension("exe");
platform->set_release_32("windows_32_release.exe");
platform->set_debug_32("windows_32_debug.exe");
platform->set_release_64("windows_64_release.exe");
platform->set_debug_64("windows_64_debug.exe");
platform->set_os_name("Windows");
- platform->set_fixup_embedded_pck_func(&fixup_embedded_pck);
EditorExport::get_singleton()->add_export_platform(platform);
}
-
-static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) {
- // Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
-
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
- if (!f) {
- return ERR_CANT_OPEN;
- }
-
- // Jump to the PE header and check the magic number
- {
- f->seek(0x3c);
- uint32_t pe_pos = f->get_32();
-
- f->seek(pe_pos);
- uint32_t magic = f->get_32();
- if (magic != 0x00004550) {
- f->close();
- return ERR_FILE_CORRUPT;
- }
- }
-
- // Process header
-
- int num_sections;
- {
- int64_t header_pos = f->get_position();
-
- f->seek(header_pos + 2);
- num_sections = f->get_16();
- f->seek(header_pos + 16);
- uint16_t opt_header_size = f->get_16();
-
- // Skip rest of header + optional header to go to the section headers
- f->seek(f->get_position() + 2 + opt_header_size);
- }
-
- // Search for the "pck" section
-
- int64_t section_table_pos = f->get_position();
-
- bool found = false;
- for (int i = 0; i < num_sections; ++i) {
- int64_t section_header_pos = section_table_pos + i * 40;
- f->seek(section_header_pos);
-
- uint8_t section_name[9];
- f->get_buffer(section_name, 8);
- section_name[8] = '\0';
-
- if (strcmp((char *)section_name, "pck") == 0) {
- // "pck" section found, let's patch!
-
- // Set virtual size to a little to avoid it taking memory (zero would give issues)
- f->seek(section_header_pos + 8);
- f->store_32(8);
-
- f->seek(section_header_pos + 16);
- f->store_32(p_embedded_size);
- f->seek(section_header_pos + 20);
- f->store_32(p_embedded_start);
-
- found = true;
- break;
- }
- }
-
- f->close();
-
- return found ? OK : ERR_FILE_CORRUPT;
-}
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 5ebc930735..f20cff90c1 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -41,6 +41,18 @@ Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPres
}
}
+Error EditorExportPlatformWindows::_export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path) {
+ FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(!f, ERR_CANT_CREATE);
+
+ f->store_line("@echo off");
+ f->store_line("title \"" + p_app_name + "\"");
+ f->store_line("\"%~dp0" + p_pkg_name + "\" \"%*\"");
+ f->store_line("pause > nul");
+
+ return OK;
+}
+
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags);
@@ -54,9 +66,32 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
err = _code_sign(p_preset, p_path);
}
+ String app_name;
+ if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") {
+ app_name = String(ProjectSettings::get_singleton()->get("application/config/name"));
+ } else {
+ app_name = "Unnamed";
+ }
+ app_name = OS::get_singleton()->get_safe_dir_name(app_name);
+
+ // Save console script.
+ if (err == OK) {
+ int con_scr = p_preset->get("debug/export_console_script");
+ if ((con_scr == 1 && p_debug) || (con_scr == 2)) {
+ String scr_path = p_path.get_basename() + ".cmd";
+ err = _export_debug_script(p_preset, app_name, p_path.get_file(), scr_path);
+ }
+ }
+
return err;
}
+List<String> EditorExportPlatformWindows::get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const {
+ List<String> list;
+ list.push_back("exe");
+ return list;
+}
+
bool EditorExportPlatformWindows::get_export_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const {
// This option is not supported by "osslsigncode", used on non-Windows host.
if (!OS::get_singleton()->has_feature("windows") && p_option == "codesign/identity_type") {
@@ -374,3 +409,74 @@ bool EditorExportPlatformWindows::can_export(const Ref<EditorExportPreset> &p_pr
return valid;
}
+
+Error EditorExportPlatformWindows::fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const {
+ // Patch the header of the "pck" section in the PE file so that it corresponds to the embedded data
+
+ FileAccess *f = FileAccess::open(p_path, FileAccess::READ_WRITE);
+ if (!f) {
+ return ERR_CANT_OPEN;
+ }
+
+ // Jump to the PE header and check the magic number
+ {
+ f->seek(0x3c);
+ uint32_t pe_pos = f->get_32();
+
+ f->seek(pe_pos);
+ uint32_t magic = f->get_32();
+ if (magic != 0x00004550) {
+ f->close();
+ return ERR_FILE_CORRUPT;
+ }
+ }
+
+ // Process header
+
+ int num_sections;
+ {
+ int64_t header_pos = f->get_position();
+
+ f->seek(header_pos + 2);
+ num_sections = f->get_16();
+ f->seek(header_pos + 16);
+ uint16_t opt_header_size = f->get_16();
+
+ // Skip rest of header + optional header to go to the section headers
+ f->seek(f->get_position() + 2 + opt_header_size);
+ }
+
+ // Search for the "pck" section
+
+ int64_t section_table_pos = f->get_position();
+
+ bool found = false;
+ for (int i = 0; i < num_sections; ++i) {
+ int64_t section_header_pos = section_table_pos + i * 40;
+ f->seek(section_header_pos);
+
+ uint8_t section_name[9];
+ f->get_buffer(section_name, 8);
+ section_name[8] = '\0';
+
+ if (strcmp((char *)section_name, "pck") == 0) {
+ // "pck" section found, let's patch!
+
+ // Set virtual size to a little to avoid it taking memory (zero would give issues)
+ f->seek(section_header_pos + 8);
+ f->store_32(8);
+
+ f->seek(section_header_pos + 16);
+ f->store_32(p_embedded_size);
+ f->seek(section_header_pos + 20);
+ f->store_32(p_embedded_start);
+
+ found = true;
+ break;
+ }
+ }
+
+ f->close();
+
+ return found ? OK : ERR_FILE_CORRUPT;
+}
diff --git a/platform/windows/export/export_plugin.h b/platform/windows/export/export_plugin.h
index 86e9d49b05..04707a5667 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -40,13 +40,16 @@
class EditorExportPlatformWindows : public EditorExportPlatformPC {
void _rcedit_add_data(const Ref<EditorExportPreset> &p_preset, const String &p_path);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
+ Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path);
public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override;
virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) override;
+ virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override;
virtual void get_export_options(List<ExportOption> *r_options) override;
virtual bool get_export_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
virtual bool can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
};
#endif
diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico
index dd611e07da..25830ffdc6 100644
--- a/platform/windows/godot.ico
+++ b/platform/windows/godot.ico
Binary files differ
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 13e3aa7883..b4669e452a 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -264,12 +264,19 @@ OS::Date OS_Windows::get_date(bool p_utc) const {
GetLocalTime(&systemtime);
}
+ //Get DST information from Windows, but only if p_utc is false.
+ TIME_ZONE_INFORMATION info;
+ bool daylight = false;
+ if (!p_utc && GetTimeZoneInformation(&info) == TIME_ZONE_ID_DAYLIGHT) {
+ daylight = true;
+ }
+
Date date;
date.day = systemtime.wDay;
date.month = Month(systemtime.wMonth);
date.weekday = Weekday(systemtime.wDayOfWeek);
date.year = systemtime.wYear;
- date.dst = false;
+ date.dst = daylight;
return date;
}
@@ -295,16 +302,19 @@ OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
daylight = true;
}
+ // Daylight Bias needs to be added to the bias if DST is in effect, or else it will not properly update.
TimeZoneInfo ret;
if (daylight) {
ret.name = info.DaylightName;
+ ret.bias = info.Bias + info.DaylightBias;
} else {
ret.name = info.StandardName;
+ ret.bias = info.Bias + info.StandardBias;
}
// Bias value returned by GetTimeZoneInformation is inverted of what we expect
// For example, on GMT-3 GetTimeZoneInformation return a Bias of 180, so invert the value to get -180
- ret.bias = -info.Bias;
+ ret.bias = -ret.bias;
return ret;
}