summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/dir_access_jandroid.cpp16
-rw-r--r--platform/android/dir_access_jandroid.h3
-rw-r--r--platform/linuxbsd/display_server_x11.cpp181
-rw-r--r--platform/linuxbsd/display_server_x11.h5
-rw-r--r--platform/macos/SCsub2
-rw-r--r--platform/macos/display_server_macos.h17
-rw-r--r--platform/macos/display_server_macos.mm85
-rw-r--r--platform/macos/godot_menu_delegate.h44
-rw-r--r--platform/macos/godot_menu_delegate.mm87
-rw-r--r--platform/macos/godot_menu_item.h4
-rw-r--r--platform/macos/godot_menu_item.mm34
-rw-r--r--platform/web/SCsub26
-rw-r--r--platform/web/detect.py70
-rw-r--r--platform/web/emscripten_helpers.py13
-rw-r--r--platform/web/export/export_plugin.cpp30
-rw-r--r--platform/web/export/export_plugin.h18
-rw-r--r--platform/web/os_web.cpp17
17 files changed, 405 insertions, 247 deletions
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 373c6e37f1..4f1ac16975 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -135,6 +135,13 @@ String DirAccessJAndroid::get_drive(int p_drive) {
}
}
+String DirAccessJAndroid::_get_root_string() const {
+ if (get_access_type() == ACCESS_FILESYSTEM) {
+ return "/";
+ }
+ return DirAccessUnix::_get_root_string();
+}
+
String DirAccessJAndroid::get_current_dir(bool p_include_drive) const {
String base = _get_root_path();
String bd = current_dir;
@@ -142,10 +149,13 @@ String DirAccessJAndroid::get_current_dir(bool p_include_drive) const {
bd = current_dir.replace_first(base, "");
}
- if (bd.begins_with("/")) {
- return _get_root_string() + bd.substr(1, bd.length());
+ String root_string = _get_root_string();
+ if (bd.begins_with(root_string)) {
+ return bd;
+ } else if (bd.begins_with("/")) {
+ return root_string + bd.substr(1, bd.length());
} else {
- return _get_root_string() + bd;
+ return root_string + bd;
}
}
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 5b7b4a9c4d..5c4f1852a9 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -91,6 +91,9 @@ public:
DirAccessJAndroid();
~DirAccessJAndroid();
+protected:
+ String _get_root_string() const override;
+
private:
int id = 0;
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 017fc3e3a2..0d619904bc 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -1823,6 +1823,47 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a
return retval;
}
+bool DisplayServerX11::_window_minimize_check(WindowID p_window) const {
+ const WindowData &wd = windows[p_window];
+
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ Atom property = XInternAtom(x11_display, "WM_STATE", True);
+ if (property == None) {
+ return false;
+ }
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+
+ int result = XGetWindowProperty(
+ x11_display,
+ wd.x11_window,
+ property,
+ 0,
+ 32,
+ False,
+ AnyPropertyType,
+ &type,
+ &format,
+ &len,
+ &remaining,
+ &data);
+
+ if (result == Success && data) {
+ long *state = (long *)data;
+ if (state[0] == WM_IconicState) {
+ XFree(data);
+ return true;
+ }
+ XFree(data);
+ }
+
+ return false;
+}
+
bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
ERR_FAIL_COND_V(!windows.has(p_window), false);
const WindowData &wd = windows[p_window];
@@ -1869,11 +1910,15 @@ bool DisplayServerX11::_window_fullscreen_check(WindowID p_window) const {
return retval;
}
-void DisplayServerX11::_validate_fullscreen_on_map(WindowID p_window) {
+void DisplayServerX11::_validate_mode_on_map(WindowID p_window) {
+ // Check if we applied any window modes that didn't take effect while unmapped
const WindowData &wd = windows[p_window];
if (wd.fullscreen && !_window_fullscreen_check(p_window)) {
- // Unmapped fullscreen attempt didn't take effect, redo...
_set_wm_fullscreen(p_window, true);
+ } else if (wd.maximized && !_window_maximize_check(p_window, "_NET_WM_STATE")) {
+ _set_wm_maximized(p_window, true);
+ } else if (wd.minimized && !_window_minimize_check(p_window)) {
+ _set_wm_minimized(p_window, true);
}
}
@@ -1911,6 +1956,37 @@ void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) {
usleep(10000);
}
}
+ wd.maximized = p_enabled;
+}
+
+void DisplayServerX11::_set_wm_minimized(WindowID p_window, bool p_enabled) {
+ WindowData &wd = windows[p_window];
+ // Using ICCCM -- Inter-Client Communication Conventions Manual
+ XEvent xev;
+ Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_change;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? WM_IconicState : WM_NormalState;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
+
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.xclient.window = wd.x11_window;
+ xev.xclient.message_type = wm_state;
+ xev.xclient.format = 32;
+ xev.xclient.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.xclient.data.l[1] = wm_hidden;
+
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ wd.minimized = p_enabled;
}
void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) {
@@ -1992,32 +2068,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- //Un-Minimize
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_NormalState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, false);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2046,31 +2097,7 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) {
//do nothing
} break;
case WINDOW_MODE_MINIMIZED: {
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- XEvent xev;
- Atom wm_change = XInternAtom(x11_display, "WM_CHANGE_STATE", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_change;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = WM_IconicState;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
-
- Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
- Atom wm_hidden = XInternAtom(x11_display, "_NET_WM_STATE_HIDDEN", False);
-
- memset(&xev, 0, sizeof(xev));
- xev.type = ClientMessage;
- xev.xclient.window = wd.x11_window;
- xev.xclient.message_type = wm_state;
- xev.xclient.format = 32;
- xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
- xev.xclient.data.l[1] = wm_hidden;
-
- XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+ _set_wm_minimized(p_window, true);
} break;
case WINDOW_MODE_EXCLUSIVE_FULLSCREEN:
case WINDOW_MODE_FULLSCREEN: {
@@ -2105,40 +2132,9 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c
return WINDOW_MODE_MAXIMIZED;
}
- { // Test minimized.
- // Using ICCCM -- Inter-Client Communication Conventions Manual
- Atom property = XInternAtom(x11_display, "WM_STATE", True);
- if (property == None) {
- return WINDOW_MODE_WINDOWED;
- }
-
- Atom type;
- int format;
- unsigned long len;
- unsigned long remaining;
- unsigned char *data = nullptr;
-
- int result = XGetWindowProperty(
- x11_display,
- wd.x11_window,
- property,
- 0,
- 32,
- False,
- AnyPropertyType,
- &type,
- &format,
- &len,
- &remaining,
- &data);
-
- if (result == Success && data) {
- long *state = (long *)data;
- if (state[0] == WM_IconicState) {
- XFree(data);
- return WINDOW_MODE_MINIMIZED;
- }
- XFree(data);
+ {
+ if (_window_minimize_check(p_window)) {
+ return WINDOW_MODE_MINIMIZED;
}
}
@@ -3658,9 +3654,6 @@ void DisplayServerX11::process_events() {
const WindowData &wd = windows[window_id];
- // Have we failed to set fullscreen while the window was unmapped?
- _validate_fullscreen_on_map(window_id);
-
XWindowAttributes xwa;
XSync(x11_display, False);
XGetWindowAttributes(x11_display, wd.x11_window, &xwa);
@@ -3671,6 +3664,9 @@ void DisplayServerX11::process_events() {
if ((xwa.map_state == IsViewable) && !wd.no_focus && !wd.is_popup) {
XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime);
}
+
+ // Have we failed to set fullscreen while the window was unmapped?
+ _validate_mode_on_map(window_id);
} break;
case Expose: {
@@ -3690,8 +3686,7 @@ void DisplayServerX11::process_events() {
case VisibilityNotify: {
DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state);
- XVisibilityEvent *visibility = (XVisibilityEvent *)&event;
- windows[window_id].minimized = (visibility->state == VisibilityFullyObscured);
+ windows[window_id].minimized = _window_minimize_check(window_id);
} break;
case LeaveNotify: {
@@ -5003,7 +4998,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
_window_changed(&xevent);
} else if (xevent.type == MapNotify) {
// Have we failed to set fullscreen while the window was unmapped?
- _validate_fullscreen_on_map(main_window);
+ _validate_mode_on_map(main_window);
}
}
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 6b9f57d78f..650598d243 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -152,6 +152,7 @@ class DisplayServerX11 : public DisplayServer {
Vector2i last_position_before_fs;
bool focused = true;
bool minimized = false;
+ bool maximized = false;
bool is_popup = false;
Rect2i parent_safe_rect;
@@ -268,10 +269,12 @@ class DisplayServerX11 : public DisplayServer {
void _update_real_mouse_position(const WindowData &wd);
bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const;
bool _window_fullscreen_check(WindowID p_window) const;
- void _validate_fullscreen_on_map(WindowID p_window);
+ bool _window_minimize_check(WindowID p_window) const;
+ void _validate_mode_on_map(WindowID p_window);
void _update_size_hints(WindowID p_window);
void _set_wm_fullscreen(WindowID p_window, bool p_enabled);
void _set_wm_maximized(WindowID p_window, bool p_enabled);
+ void _set_wm_minimized(WindowID p_window, bool p_enabled);
void _update_context(WindowData &wd);
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index d0856c709a..bbd461fba9 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -17,6 +17,8 @@ files = [
"godot_window.mm",
"key_mapping_macos.mm",
"godot_main_macos.mm",
+ "godot_menu_delegate.mm",
+ "godot_menu_item.mm",
"dir_access_macos.mm",
"tts_macos.mm",
"joypad_macos.cpp",
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index a08667a259..cd457836de 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -140,6 +140,7 @@ private:
int key_event_pos = 0;
id tts = nullptr;
+ id menu_delegate = nullptr;
Point2i im_selection;
String im_text;
@@ -227,14 +228,14 @@ public:
virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
- virtual int 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 int 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 int 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 int 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 int 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 int 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 int 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 int global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1) override;
+ virtual int global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int 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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int 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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int 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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
+ virtual int 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 Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1) override;
virtual int 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;
@@ -244,6 +245,7 @@ public:
virtual bool global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const 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 Callable global_menu_get_item_key_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;
@@ -259,6 +261,7 @@ public:
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_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_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;
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index b06ae9f27c..c117713c2b 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -31,6 +31,7 @@
#include "display_server_macos.h"
#include "godot_content_view.h"
+#include "godot_menu_delegate.h"
#include "godot_menu_item.h"
#include "godot_window.h"
#include "godot_window_delegate.h"
@@ -95,6 +96,7 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
if (!submenu.has(p_menu_root)) {
NSMenu *n_menu = [[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:p_menu_root.utf8().get_data()]];
[n_menu setAutoenablesItems:NO];
+ [n_menu setDelegate:menu_delegate];
submenu[p_menu_root] = n_menu;
}
menu = submenu[p_menu_root];
@@ -754,7 +756,7 @@ NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const
return nullptr;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -762,6 +764,7 @@ int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const St
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
@@ -772,7 +775,7 @@ int DisplayServerMacOS::global_menu_add_item(const String &p_menu_root, const St
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -780,6 +783,7 @@ int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, co
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
@@ -790,7 +794,7 @@ int DisplayServerMacOS::global_menu_add_check_item(const String &p_menu_root, co
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -798,6 +802,7 @@ int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, con
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = 0;
@@ -817,7 +822,7 @@ int DisplayServerMacOS::global_menu_add_icon_item(const String &p_menu_root, con
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -825,6 +830,7 @@ int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_roo
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
obj->max_states = 0;
@@ -844,7 +850,7 @@ int DisplayServerMacOS::global_menu_add_icon_check_item(const String &p_menu_roo
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -852,6 +858,7 @@ int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_ro
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
@@ -862,7 +869,7 @@ int DisplayServerMacOS::global_menu_add_radio_check_item(const String &p_menu_ro
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
int out = -1;
@@ -870,6 +877,7 @@ int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_me
if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
obj->max_states = 0;
@@ -889,30 +897,15 @@ int DisplayServerMacOS::global_menu_add_icon_radio_check_item(const String &p_me
return out;
}
-int DisplayServerMacOS::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) {
+int DisplayServerMacOS::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 Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
_THREAD_SAFE_METHOD_
- NSMenu *menu = _get_menu_root(p_menu_root);
int out = -1;
- if (menu) {
- String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
- NSMenuItem *menu_item;
- int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems];
- if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) {
- p_index = [menu numberOfItems];
- } else if (p_index < 0) {
- p_index = item_count;
- } else {
- if (menu == [NSApp mainMenu]) { // Skip Apple menu.
- p_index++;
- }
- p_index = CLAMP(p_index, 0, item_count);
- }
- menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
- out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index;
-
+ NSMenuItem *menu_item = _menu_add_item(p_menu_root, p_label, p_accel, p_index, &out);
+ if (menu_item) {
GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = p_callback;
+ obj->key_callback = p_key_callback;
obj->meta = p_tag;
obj->checkable_type = CHECKABLE_TYPE_NONE;
obj->max_states = p_max_states;
@@ -1104,6 +1097,27 @@ Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_
return Callable();
}
+Callable DisplayServerMacOS::global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const {
+ _THREAD_SAFE_METHOD_
+
+ const NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ ERR_FAIL_COND_V(p_idx < 0, Callable());
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable());
+ const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ if (obj) {
+ return obj->key_callback;
+ }
+ }
+ }
+ return Callable();
+}
+
Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const {
_THREAD_SAFE_METHOD_
@@ -1401,6 +1415,25 @@ void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root
}
}
+void DisplayServerMacOS::global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) {
+ _THREAD_SAFE_METHOD_
+
+ NSMenu *menu = _get_menu_root(p_menu_root);
+ if (menu) {
+ ERR_FAIL_COND(p_idx < 0);
+ if (menu == [NSApp mainMenu]) { // Skip Apple menu.
+ p_idx++;
+ }
+ ERR_FAIL_COND(p_idx >= [menu numberOfItems]);
+ NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
+ if (menu_item) {
+ GodotMenuItem *obj = [menu_item representedObject];
+ ERR_FAIL_COND(!obj);
+ obj->key_callback = p_key_callback;
+ }
+ }
+}
+
void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) {
_THREAD_SAFE_METHOD_
@@ -3477,6 +3510,8 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[main_menu setSubmenu:apple_menu forItem:menu_item];
[main_menu setAutoenablesItems:NO];
+ menu_delegate = [[GodotMenuDelegate alloc] init];
+
//!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback
rendering_driver = p_rendering_driver;
diff --git a/platform/macos/godot_menu_delegate.h b/platform/macos/godot_menu_delegate.h
new file mode 100644
index 0000000000..805ac0c4a3
--- /dev/null
+++ b/platform/macos/godot_menu_delegate.h
@@ -0,0 +1,44 @@
+/*************************************************************************/
+/* godot_menu_delegate.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 GODOT_MENU_DELEGATE_H
+#define GODOT_MENU_DELEGATE_H
+
+#import <AppKit/AppKit.h>
+#import <Foundation/Foundation.h>
+
+@interface GodotMenuDelegate : NSObject <NSMenuDelegate> {
+}
+
+- (void)doNothing:(id)sender;
+
+@end
+
+#endif // GODOT_MENU_DELEGATE_H
diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm
new file mode 100644
index 0000000000..bd394d8415
--- /dev/null
+++ b/platform/macos/godot_menu_delegate.mm
@@ -0,0 +1,87 @@
+/*************************************************************************/
+/* godot_menu_delegate.mm */
+/*************************************************************************/
+/* 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 "godot_menu_delegate.h"
+
+#include "display_server_macos.h"
+#include "godot_menu_item.h"
+#include "key_mapping_macos.h"
+
+@implementation GodotMenuDelegate
+
+- (void)doNothing:(id)sender {
+}
+
+- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action {
+ NSString *ev_key = [[event charactersIgnoringModifiers] lowercaseString];
+ NSUInteger ev_modifiers = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+ for (int i = 0; i < [menu numberOfItems]; i++) {
+ const NSMenuItem *menu_item = [menu itemAtIndex:i];
+ if ([menu_item isEnabled] && [[menu_item keyEquivalent] compare:ev_key] == NSOrderedSame) {
+ NSUInteger item_modifiers = [menu_item keyEquivalentModifierMask];
+
+ if (ev_modifiers == item_modifiers) {
+ GodotMenuItem *value = [menu_item representedObject];
+ if (value->key_callback != Callable()) {
+ // If custom callback is set, use it.
+ Variant tag = value->meta;
+ Variant *tagp = &tag;
+ Variant ret;
+ Callable::CallError ce;
+ value->key_callback.callp((const Variant **)&tagp, 1, ret, ce);
+ } else {
+ // Otherwise redirect event to the engine.
+ if (DisplayServer::get_singleton()) {
+ DisplayServerMacOS::KeyEvent ke;
+
+ ke.window_id = DisplayServer::MAIN_WINDOW_ID;
+ ke.macos_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.keycode = KeyMappingMacOS::remap_key([event keyCode], [event modifierFlags]);
+ ke.physical_keycode = KeyMappingMacOS::translate_key([event keyCode]);
+ ke.raw = false;
+ ke.unicode = 0;
+
+ reinterpret_cast<DisplayServerMacOS *>(DisplayServer::get_singleton())->push_to_key_event_buffer(ke);
+ }
+ }
+
+ // Suppress default menu action.
+ *target = self;
+ *action = @selector(doNothing:);
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
+@end
diff --git a/platform/macos/godot_menu_item.h b/platform/macos/godot_menu_item.h
index e0b9f41632..e96f5dc1cf 100644
--- a/platform/macos/godot_menu_item.h
+++ b/platform/macos/godot_menu_item.h
@@ -45,6 +45,7 @@ enum GlobalMenuCheckType {
@interface GodotMenuItem : NSObject {
@public
Callable callback;
+ Callable key_callback;
Variant meta;
GlobalMenuCheckType checkable_type;
int max_states;
@@ -54,7 +55,4 @@ enum GlobalMenuCheckType {
@end
-@implementation GodotMenuItem
-@end
-
#endif // GODOT_MENU_ITEM_H
diff --git a/platform/macos/godot_menu_item.mm b/platform/macos/godot_menu_item.mm
new file mode 100644
index 0000000000..ea35e35d19
--- /dev/null
+++ b/platform/macos/godot_menu_item.mm
@@ -0,0 +1,34 @@
+/*************************************************************************/
+/* godot_menu_item.mm */
+/*************************************************************************/
+/* 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 "godot_menu_item.h"
+
+@implementation GodotMenuItem
+@end
diff --git a/platform/web/SCsub b/platform/web/SCsub
index 78d7ce4074..ae9d628857 100644
--- a/platform/web/SCsub
+++ b/platform/web/SCsub
@@ -35,18 +35,17 @@ for ext in env["JS_EXTERNS"]:
sys_env["ENV"]["EMCC_CLOSURE_ARGS"] += " --externs " + ext.abspath
build = []
-if env["gdnative_enabled"]:
- build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
- if env["threads_enabled"]:
- build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
+build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm", "#bin/godot${PROGSUFFIX}.worker.js"]
+if env["dlink_enabled"]:
# Reset libraries. The main runtime will only link emscripten libraries, not godot ones.
sys_env["LIBS"] = []
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
sys_env.Append(LIBS=["idbfs.js"])
# Configure it as a main module (dynamic linking support).
+ sys_env["CCFLAGS"].remove("SIDE_MODULE=2")
+ sys_env["LINKFLAGS"].remove("SIDE_MODULE=2")
sys_env.Append(CCFLAGS=["-s", "MAIN_MODULE=1"])
sys_env.Append(LINKFLAGS=["-s", "MAIN_MODULE=1"])
- sys_env.Append(CCFLAGS=["-s", "EXPORT_ALL=1"])
sys_env.Append(LINKFLAGS=["-s", "EXPORT_ALL=1"])
sys_env.Append(LINKFLAGS=["-s", "WARN_ON_UNDEFINED_SYMBOLS=0"])
# Force exporting the standard library (printf, malloc, etc.)
@@ -55,16 +54,9 @@ if env["gdnative_enabled"]:
sys = sys_env.Program(build_targets, ["web_runtime.cpp"])
# The side library, containing all Godot code.
- wasm_env = env.Clone()
- wasm_env.Append(CPPDEFINES=["WASM_GDNATIVE"]) # So that OS knows it can run GDNative libraries.
- wasm_env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
- wasm_env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
- wasm = wasm_env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
+ wasm = env.add_program("#bin/godot.side${PROGSUFFIX}.wasm", web_files)
build = sys + [wasm[0]]
else:
- build_targets = ["#bin/godot${PROGSUFFIX}.js", "#bin/godot${PROGSUFFIX}.wasm"]
- if env["threads_enabled"]:
- build_targets.append("#bin/godot${PROGSUFFIX}.worker.js")
# We use IDBFS. Since Emscripten 1.39.1 it needs to be linked explicitly.
sys_env.Append(LIBS=["idbfs.js"])
build = sys_env.Program(build_targets, web_files + ["web_runtime.cpp"])
@@ -88,6 +80,8 @@ wrap_list = [
]
js_wrapped = env.Textfile("#bin/godot", [env.File(f) for f in wrap_list], TEXTFILESUFFIX="${PROGSUFFIX}.wrapped.js")
-# Extra will be the thread worker, or the GDNative side, or None
-extra = build[2:] if len(build) > 2 else None
-env.CreateTemplateZip(js_wrapped, build[1], extra)
+# 0 - unwrapped js file (use wrapped one instead)
+# 1 - wasm file
+# 2 - worker file
+# 3 - wasm side (when dlink is enabled).
+env.CreateTemplateZip(js_wrapped, build[1], build[2], build[3] if len(build) > 3 else None)
diff --git a/platform/web/detect.py b/platform/web/detect.py
index ae0ff2c4ea..b1c1dd48a9 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -38,8 +38,9 @@ def get_opts():
BoolVariable("use_safe_heap", "Use Emscripten SAFE_HEAP sanitizer", False),
# eval() can be a security concern, so it can be disabled.
BoolVariable("javascript_eval", "Enable JavaScript eval interface", True),
- BoolVariable("threads_enabled", "Enable WebAssembly Threads support (limited browser support)", True),
- BoolVariable("gdnative_enabled", "Enable WebAssembly GDNative support (produces bigger binaries)", False),
+ BoolVariable(
+ "dlink_enabled", "Enable WebAssembly dynamic linking (GDExtension support). Produces bigger binaries", False
+ ),
BoolVariable("use_closure_compiler", "Use closure compiler to minimize JavaScript code", False),
]
@@ -50,6 +51,13 @@ def get_flags():
("tools", False),
("builtin_pcre2_with_jit", False),
("vulkan", False),
+ # Use -Os to prioritize optimizing for reduced file size. This is
+ # particularly valuable for the web platform because it directly
+ # decreases download time.
+ # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
+ # 100 KiB over -Os, which does not justify the negative impact on
+ # run-time performance.
+ ("optimize", "size"),
]
@@ -71,15 +79,12 @@ def configure(env):
## Build type
if env["target"].startswith("release"):
- # Use -Os to prioritize optimizing for reduced file size. This is
- # particularly valuable for the web platform because it directly
- # decreases download time.
- # -Os reduces file size by around 5 MiB over -O3. -Oz only saves about
- # 100 KiB over -Os, which does not justify the negative impact on
- # run-time performance.
- if env["optimize"] != "none":
+ if env["optimize"] == "size":
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
+ elif env["optimize"] == "speed":
+ env.Append(CCFLAGS=["-O3"])
+ env.Append(LINKFLAGS=["-O3"])
if env["target"] == "release_debug":
# Retain function names for backtraces at the cost of file size.
@@ -93,21 +98,11 @@ def configure(env):
env.Append(LINKFLAGS=["-s", "ASSERTIONS=1"])
if env["tools"]:
- if not env["threads_enabled"]:
- print('Note: Forcing "threads_enabled=yes" as it is required for the web editor.')
- env["threads_enabled"] = "yes"
if env["initial_memory"] < 64:
print('Note: Forcing "initial_memory=64" as it is required for the web editor.')
env["initial_memory"] = 64
- env.Append(CCFLAGS=["-frtti"])
- elif env["builtin_icu"]:
- env.Append(CCFLAGS=["-fno-exceptions", "-frtti"])
else:
- # Disable exceptions and rtti on non-tools (template) builds
- # These flags help keep the file size down.
- env.Append(CCFLAGS=["-fno-exceptions", "-fno-rtti"])
- # Don't use dynamic_cast, necessary with no-rtti.
- env.Append(CPPDEFINES=["NO_SAFE_CAST"])
+ env.Append(CPPFLAGS=["-fno-exceptions"])
env.Append(LINKFLAGS=["-s", "INITIAL_MEMORY=%sMB" % env["initial_memory"]])
@@ -171,9 +166,9 @@ def configure(env):
env["ARCOM_POSIX"] = env["ARCOM"].replace("$TARGET", "$TARGET.posix").replace("$SOURCES", "$SOURCES.posix")
env["ARCOM"] = "${TEMPFILE(ARCOM_POSIX)}"
- # All intermediate files are just LLVM bitcode.
+ # All intermediate files are just object files.
env["OBJPREFIX"] = ""
- env["OBJSUFFIX"] = ".bc"
+ env["OBJSUFFIX"] = ".o"
env["PROGPREFIX"] = ""
# Program() output consists of multiple files, so specify suffixes manually at builder.
env["PROGSUFFIX"] = ""
@@ -196,31 +191,22 @@ def configure(env):
env.Append(CPPDEFINES=["JAVASCRIPT_EVAL_ENABLED"])
# Thread support (via SharedArrayBuffer).
- if env["threads_enabled"]:
- env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
- env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
- env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
- env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
- env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
- env.extra_suffix = ".threads" + env.extra_suffix
- else:
- env.Append(CPPDEFINES=["NO_THREADS"])
+ env.Append(CPPDEFINES=["PTHREAD_NO_RENAME"])
+ env.Append(CCFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "USE_PTHREADS=1"])
+ env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
+ env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
- if env["gdnative_enabled"]:
+ if env["dlink_enabled"]:
cc_version = get_compiler_version(env)
cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
- if cc_semver < (2, 0, 10):
- print("GDNative support requires emscripten >= 2.0.10, detected: %s.%s.%s" % cc_semver)
+ if cc_semver < (3, 1, 14):
+ print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
sys.exit(255)
- if env["threads_enabled"] and cc_semver < (3, 1, 14):
- print("Threads and GDNative requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
- sys.exit(255)
- env.Append(CCFLAGS=["-s", "RELOCATABLE=1"])
- env.Append(LINKFLAGS=["-s", "RELOCATABLE=1"])
- # Weak symbols are broken upstream: https://github.com/emscripten-core/emscripten/issues/12819
- env.Append(CPPDEFINES=["ZSTD_HAVE_WEAK_SYMBOLS=0"])
- env.extra_suffix = ".gdnative" + env.extra_suffix
+ env.Append(CCFLAGS=["-s", "SIDE_MODULE=2"])
+ env.Append(LINKFLAGS=["-s", "SIDE_MODULE=2"])
+ env.extra_suffix = ".dlink" + env.extra_suffix
# Reduce code size by generating less support code (e.g. skip NodeJS support).
env.Append(LINKFLAGS=["-s", "ENVIRONMENT=web,worker"])
diff --git a/platform/web/emscripten_helpers.py b/platform/web/emscripten_helpers.py
index b7b1026ef7..6045bc6fbd 100644
--- a/platform/web/emscripten_helpers.py
+++ b/platform/web/emscripten_helpers.py
@@ -37,26 +37,25 @@ def create_engine_file(env, target, source, externs):
return env.Textfile(target, [env.File(s) for s in source])
-def create_template_zip(env, js, wasm, extra):
+def create_template_zip(env, js, wasm, worker, side):
binary_name = "godot.tools" if env["tools"] else "godot"
zip_dir = env.Dir("#bin/.web_zip")
in_files = [
js,
wasm,
+ worker,
"#platform/web/js/libs/audio.worklet.js",
]
out_files = [
zip_dir.File(binary_name + ".js"),
zip_dir.File(binary_name + ".wasm"),
+ zip_dir.File(binary_name + ".worker.js"),
zip_dir.File(binary_name + ".audio.worklet.js"),
]
- # GDNative/Threads specific
- if env["gdnative_enabled"]:
- in_files.append(extra.pop()) # Runtime
+ # Dynamic linking (extensions) specific.
+ if env["dlink_enabled"]:
+ in_files.append(side) # Side wasm (contains the actual Godot code).
out_files.append(zip_dir.File(binary_name + ".side.wasm"))
- if env["threads_enabled"]:
- in_files.append(extra.pop()) # Worker
- out_files.append(zip_dir.File(binary_name + ".worker.js"))
service_worker = "#misc/dist/html/service-worker.js"
if env["tools"]:
diff --git a/platform/web/export/export_plugin.cpp b/platform/web/export/export_plugin.cpp
index 2cd8ec88ef..9971481459 100644
--- a/platform/web/export/export_plugin.cpp
+++ b/platform/web/export/export_plugin.cpp
@@ -201,7 +201,7 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
// Service worker
const String dir = p_path.get_base_dir();
const String name = p_path.get_file().get_basename();
- const ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
HashMap<String, String> replaces;
replaces["@GODOT_VERSION@"] = String::num_int64(OS::get_singleton()->get_unix_time()) + "|" + String::num_int64(OS::get_singleton()->get_ticks_usec());
replaces["@GODOT_NAME@"] = proj_name.substr(0, 16);
@@ -216,17 +216,15 @@ Error EditorExportPlatformWeb::_build_pwa(const Ref<EditorExportPreset> &p_prese
cache_files.push_back(name + ".icon.png");
cache_files.push_back(name + ".apple-touch-icon.png");
}
- if (mode & EXPORT_MODE_THREADS) {
- cache_files.push_back(name + ".worker.js");
- cache_files.push_back(name + ".audio.worklet.js");
- }
+ cache_files.push_back(name + ".worker.js");
+ cache_files.push_back(name + ".audio.worklet.js");
replaces["@GODOT_CACHE@"] = Variant(cache_files).to_json_string();
// Heavy files that are cached on demand.
Array opt_cache_files;
opt_cache_files.push_back(name + ".wasm");
opt_cache_files.push_back(name + ".pck");
- if (mode & EXPORT_MODE_GDNATIVE) {
+ if (extensions) {
opt_cache_files.push_back(name + ".side.wasm");
for (int i = 0; i < p_shared_objects.size(); i++) {
opt_cache_files.push_back(p_shared_objects[i].path.get_file());
@@ -317,20 +315,14 @@ void EditorExportPlatformWeb::get_preset_features(const Ref<EditorExportPreset>
r_features->push_back("etc2");
}
}
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- if (mode & EXPORT_MODE_THREADS) {
- r_features->push_back("threads");
- }
- if (mode & EXPORT_MODE_GDNATIVE) {
- r_features->push_back("wasm32");
- }
+ r_features->push_back("wasm32");
}
void EditorExportPlatformWeb::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, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type.
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "variant/extensions_support"), false)); // Export type.
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
@@ -374,11 +366,11 @@ bool EditorExportPlatformWeb::has_valid_export_configuration(const Ref<EditorExp
String err;
bool valid = false;
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
// Look for export templates (first official, and if defined custom templates).
- bool dvalid = exists_export_template(_get_template_name(mode, true), &err);
- bool rvalid = exists_export_template(_get_template_name(mode, false), &err);
+ bool dvalid = exists_export_template(_get_template_name(extensions, true), &err);
+ bool rvalid = exists_export_template(_get_template_name(extensions, false), &err);
if (p_preset->get("custom_template/debug") != "") {
dvalid = FileAccess::exists(p_preset->get("custom_template/debug"));
@@ -456,8 +448,8 @@ Error EditorExportPlatformWeb::export_project(const Ref<EditorExportPreset> &p_p
String template_path = p_debug ? custom_debug : custom_release;
template_path = template_path.strip_edges();
if (template_path.is_empty()) {
- ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type");
- template_path = find_export_template(_get_template_name(mode, p_debug));
+ bool extensions = (bool)p_preset->get("variant/extensions_support");
+ template_path = find_export_template(_get_template_name(extensions, p_debug));
}
if (!DirAccess::exists(base_dir)) {
diff --git a/platform/web/export/export_plugin.h b/platform/web/export/export_plugin.h
index 9c1bf2a5ef..5b7ce5f708 100644
--- a/platform/web/export/export_plugin.h
+++ b/platform/web/export/export_plugin.h
@@ -57,20 +57,10 @@ class EditorExportPlatformWeb : public EditorExportPlatform {
Mutex server_lock;
Thread server_thread;
- enum ExportMode {
- EXPORT_MODE_NORMAL = 0,
- EXPORT_MODE_THREADS = 1,
- EXPORT_MODE_GDNATIVE = 2,
- EXPORT_MODE_THREADS_GDNATIVE = 3,
- };
-
- String _get_template_name(ExportMode p_mode, bool p_debug) const {
- String name = "webassembly";
- if (p_mode & EXPORT_MODE_GDNATIVE) {
- name += "_gdnative";
- }
- if (p_mode & EXPORT_MODE_THREADS) {
- name += "_threads";
+ String _get_template_name(bool p_extension, bool p_debug) const {
+ String name = "web";
+ if (p_extension) {
+ name += "_dlink";
}
if (p_debug) {
name += "_debug.zip";
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index 461dc71119..f9714f25e7 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -140,26 +140,9 @@ int OS_Web::get_processor_count() const {
}
bool OS_Web::_check_internal_feature_support(const String &p_feature) {
- if (p_feature == "html5" || p_feature == "web") {
- return true;
- }
-
-#ifdef JAVASCRIPT_EVAL_ENABLED
if (p_feature == "web") {
return true;
}
-#endif
-#ifndef NO_THREADS
- if (p_feature == "threads") {
- return true;
- }
-#endif
-#if WASM_GDNATIVE
- if (p_feature == "wasm32") {
- return true;
- }
-#endif
-
return false;
}