summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/javascript/export/export_plugin.cpp9
-rw-r--r--platform/javascript/package-lock.json12
-rw-r--r--platform/linuxbsd/display_server_x11.cpp6
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/linuxbsd/export/export.cpp114
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp130
-rw-r--r--platform/linuxbsd/export/export_plugin.h5
-rw-r--r--platform/osx/display_server_osx.h41
-rw-r--r--platform/osx/display_server_osx.mm545
-rw-r--r--platform/osx/godot_menu_item.h11
-rw-r--r--platform/uwp/export/export_plugin.cpp8
-rw-r--r--platform/windows/display_server_windows.cpp10
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--platform/windows/export/export.cpp79
-rw-r--r--platform/windows/export/export_plugin.cpp81
-rw-r--r--platform/windows/export/export_plugin.h3
16 files changed, 817 insertions, 241 deletions
diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp
index 4448acccc2..84694461cf 100644
--- a/platform/javascript/export/export_plugin.cpp
+++ b/platform/javascript/export/export_plugin.cpp
@@ -360,6 +360,15 @@ Ref<Texture2D> EditorExportPlatformJavaScript::get_logo() const {
}
bool EditorExportPlatformJavaScript::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the HTML5 platform currently as there
+ // is no suitable renderer to use with them. So we forbid exporting and tell
+ // users why. This is skipped in DEV_ENABLED so that contributors can still test
+ // the pipeline once we start having WebGL or WebGPU support.
+ r_error = "The HTML5 platform is currently not supported in Godot 4.0, as there is no suitable renderer for it.\n";
+ return false;
+#endif
+
String err;
bool valid = false;
ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
diff --git a/platform/javascript/package-lock.json b/platform/javascript/package-lock.json
index 35f864f01a..f72cde955a 100644
--- a/platform/javascript/package-lock.json
+++ b/platform/javascript/package-lock.json
@@ -1884,9 +1884,9 @@
}
},
"node_modules/minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"node_modules/mkdirp": {
@@ -4444,9 +4444,9 @@
}
},
"minimist": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
- "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
+ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
"dev": true
},
"mkdirp": {
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 07cb6a23e8..2ddccdb8bf 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -363,15 +363,15 @@ DisplayServerX11::MouseMode DisplayServerX11::mouse_get_mode() const {
return mouse_mode;
}
-void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) {
+void DisplayServerX11::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (mouse_mode == MOUSE_MODE_CAPTURED) {
- last_mouse_pos = p_to;
+ last_mouse_pos = p_position;
} else {
WindowID window_id = windows.has(last_focused_window) ? last_focused_window : MAIN_WINDOW_ID;
XWarpPointer(x11_display, None, windows[window_id].x11_window,
- 0, 0, 0, 0, (int)p_to.x, (int)p_to.y);
+ 0, 0, 0, 0, (int)p_position.x, (int)p_position.y);
}
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 63d32d939d..0f44aa4b11 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -301,7 +301,7 @@ public:
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
- virtual void mouse_warp_to_position(const Point2i &p_to) override;
+ virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
virtual MouseButton mouse_get_button_state() const override;
diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp
index 796e82594a..ec83e52f09 100644
--- a/platform/linuxbsd/export/export.cpp
+++ b/platform/linuxbsd/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_linuxbsd_exporter() {
Ref<EditorExportPlatformLinuxBSD> platform;
platform.instantiate();
@@ -44,120 +42,10 @@ 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");
- platform->set_release_64("linux_x11_64_release");
- 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
index 99f5b82b34..24906fa3fb 100644
--- a/platform/linuxbsd/export/export_plugin.cpp
+++ b/platform/linuxbsd/export/export_plugin.cpp
@@ -72,3 +72,133 @@ Error EditorExportPlatformLinuxBSD::export_project(const Ref<EditorExportPreset>
return err;
}
+
+void EditorExportPlatformLinuxBSD::set_extension(const String &p_extension, const String &p_feature_key) {
+ extensions[p_feature_key] = p_extension;
+}
+
+String EditorExportPlatformLinuxBSD::get_template_file_name(const String &p_target, const String &p_arch) const {
+ return "linux_x11_" + p_arch + "_" + p_target;
+}
+
+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
index f482ddce3d..f46fc68e1d 100644
--- a/platform/linuxbsd/export/export_plugin.h
+++ b/platform/linuxbsd/export/export_plugin.h
@@ -38,10 +38,15 @@
#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 String get_template_file_name(const String &p_target, const String &p_arch) 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/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index cc9ac162ea..fa3091ff81 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;
@@ -248,7 +271,7 @@ public:
virtual MouseMode mouse_get_mode() const override;
bool update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSPoint &r_mpos, NSTimeInterval p_timestamp);
- virtual void mouse_warp_to_position(const Point2i &p_to) override;
+ virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
void mouse_set_button_state(MouseButton p_state);
virtual MouseButton mouse_get_button_state() const override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 89ca6e50ec..6cdadcae39 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_
@@ -1154,7 +1646,7 @@ bool DisplayServerOSX::update_mouse_wrap(WindowData &p_wd, NSPoint &r_delta, NSP
return false;
}
-void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
+void DisplayServerOSX::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (mouse_mode != MOUSE_MODE_CAPTURED) {
@@ -1164,7 +1656,7 @@ void DisplayServerOSX::mouse_warp_to_position(const Point2i &p_to) {
// Local point in window coords.
const NSRect contentRect = [wd.window_view frame];
const float scale = screen_get_max_scale();
- NSRect pointInWindowRect = NSMakeRect(p_to.x / scale, contentRect.size.height - (p_to.y / scale - 1), 0, 0);
+ NSRect pointInWindowRect = NSMakeRect(p_position.x / scale, contentRect.size.height - (p_position.y / scale - 1), 0, 0);
NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
// Point in scren coords.
@@ -1190,7 +1682,11 @@ Point2i DisplayServerOSX::mouse_get_position() const {
for (NSScreen *screen in [NSScreen screens]) {
NSRect frame = [screen frame];
if (NSMouseInRect(mouse_pos, frame, NO)) {
- return Vector2i((int)mouse_pos.x, (int)-mouse_pos.y) * scale + _get_screens_origin();
+ Vector2i pos = Vector2i((int)mouse_pos.x, (int)mouse_pos.y);
+ pos *= scale;
+ pos -= _get_screens_origin();
+ pos.y *= -1;
+ return pos;
}
}
return Vector2i();
@@ -2628,11 +3124,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 +3158,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/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 230e5c749c..88343d6f85 100644
--- a/platform/uwp/export/export_plugin.cpp
+++ b/platform/uwp/export/export_plugin.cpp
@@ -131,6 +131,14 @@ void EditorExportPlatformUWP::get_export_options(List<ExportOption> *r_options)
}
bool EditorExportPlatformUWP::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const {
+#ifndef DEV_ENABLED
+ // We don't provide export templates for the UWP platform currently as it
+ // has not been ported for Godot 4.0. This is skipped in DEV_ENABLED so that
+ // contributors can still test the pipeline if/when we can build it again.
+ r_error = "The UWP platform is currently not supported in Godot 4.0.\n";
+ return false;
+#endif
+
String err;
bool valid = false;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index d243d4c05d..16323dcc13 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -150,7 +150,7 @@ DisplayServer::MouseMode DisplayServerWindows::mouse_get_mode() const {
return mouse_mode;
}
-void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) {
+void DisplayServerWindows::warp_mouse(const Point2i &p_position) {
_THREAD_SAFE_METHOD_
if (!windows.has(last_focused_window)) {
@@ -158,12 +158,12 @@ void DisplayServerWindows::mouse_warp_to_position(const Point2i &p_to) {
}
if (mouse_mode == MOUSE_MODE_CAPTURED) {
- old_x = p_to.x;
- old_y = p_to.y;
+ old_x = p_position.x;
+ old_y = p_position.y;
} else {
POINT p;
- p.x = p_to.x;
- p.y = p_to.y;
+ p.x = p_position.x;
+ p.y = p_position.y;
ClientToScreen(windows[last_focused_window].hWnd, &p);
SetCursorPos(p.x, p.y);
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index a56a2b83ac..71fedf2bca 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -457,7 +457,7 @@ public:
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
- virtual void mouse_warp_to_position(const Point2i &p_to) override;
+ virtual void warp_mouse(const Point2i &p_position) override;
virtual Point2i mouse_get_position() const override;
virtual MouseButton mouse_get_button_state() const override;
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 17a24c08bf..0fa2913218 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,7 @@ 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 7b9cb59896..e627253739 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -86,6 +86,16 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>
return err;
}
+String EditorExportPlatformWindows::get_template_file_name(const String &p_target, const String &p_arch) const {
+ return "windows_" + p_arch + "_" + p_target + ".exe";
+}
+
+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") {
@@ -403,3 +413,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 b40e872461..39d1cf4c77 100644
--- a/platform/windows/export/export_plugin.h
+++ b/platform/windows/export/export_plugin.h
@@ -45,9 +45,12 @@ class EditorExportPlatformWindows : public EditorExportPlatformPC {
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 String get_template_file_name(const String &p_target, const String &p_arch) const override;
+ virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) const override;
};
#endif