summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java24
-rw-r--r--platform/iphone/export/export.cpp7
-rw-r--r--platform/iphone/godot_view_gesture_recognizer.h2
-rw-r--r--platform/javascript/SCsub2
-rw-r--r--platform/javascript/audio_driver_javascript.h22
-rw-r--r--platform/javascript/display_server_javascript.cpp44
-rw-r--r--platform/javascript/display_server_javascript.h104
-rw-r--r--platform/javascript/engine/engine.js20
-rw-r--r--platform/javascript/export/export.cpp2
-rw-r--r--platform/javascript/javascript_main.cpp77
-rw-r--r--platform/javascript/native/utils.js75
-rw-r--r--platform/javascript/os_javascript.cpp71
-rw-r--r--platform/javascript/os_javascript.h49
-rw-r--r--platform/linuxbsd/detect.py6
-rw-r--r--platform/linuxbsd/display_server_x11.cpp40
-rw-r--r--platform/linuxbsd/display_server_x11.h2
-rw-r--r--platform/linuxbsd/platform_config.h12
-rw-r--r--platform/osx/display_server_osx.h3
-rw-r--r--platform/osx/display_server_osx.mm36
-rw-r--r--platform/server/platform_config.h13
-rw-r--r--platform/windows/SCsub6
-rw-r--r--platform/windows/detect.py2
-rw-r--r--platform/windows/display_server_windows.cpp33
-rw-r--r--platform/windows/display_server_windows.h4
24 files changed, 439 insertions, 217 deletions
diff --git a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
index 138c2de94c..5aa48d87da 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/FullScreenGodotApp.java
@@ -34,6 +34,8 @@ import android.content.Intent;
import android.os.Bundle;
import android.view.KeyEvent;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
/**
@@ -43,13 +45,18 @@ import androidx.fragment.app.FragmentActivity;
* within an Android app.
*/
public abstract class FullScreenGodotApp extends FragmentActivity {
- protected Godot godotFragment;
+ @Nullable
+ private Godot godotFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.godot_app_layout);
- godotFragment = new Godot();
+ godotFragment = initGodotInstance();
+ if (godotFragment == null) {
+ throw new IllegalStateException("Godot instance must be non-null.");
+ }
+
getSupportFragmentManager().beginTransaction().replace(R.id.godot_fragment_container, godotFragment).setPrimaryNavigationFragment(godotFragment).commitNowAllowingStateLoss();
}
@@ -76,4 +83,17 @@ public abstract class FullScreenGodotApp extends FragmentActivity {
}
return super.onKeyMultiple(inKeyCode, repeatCount, event);
}
+
+ /**
+ * Used to initialize the Godot fragment instance in {@link FullScreenGodotApp#onCreate(Bundle)}.
+ */
+ @NonNull
+ protected Godot initGodotInstance() {
+ return new Godot();
+ }
+
+ @Nullable
+ protected final Godot getGodotFragment() {
+ return godotFragment;
+ }
}
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 97f954ebb2..19f7c8e482 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -160,9 +160,8 @@ public:
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
String driver = ProjectSettings::get_singleton()->get("rendering/quality/driver/driver_name");
- if (driver == "GLES2") {
- r_features->push_back("etc");
- } else if (driver == "Vulkan") {
+ r_features->push_back("pvrtc");
+ if (driver == "Vulkan") {
// FIXME: Review if this is correct.
r_features->push_back("etc2");
}
@@ -1649,7 +1648,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
}
}
- String etc_error = test_etc2();
+ String etc_error = test_etc2_or_pvrtc();
if (etc_error != String()) {
valid = false;
err += etc_error;
diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/iphone/godot_view_gesture_recognizer.h
index ca3bd808d1..8d84914712 100644
--- a/platform/iphone/godot_view_gesture_recognizer.h
+++ b/platform/iphone/godot_view_gesture_recognizer.h
@@ -32,7 +32,7 @@
// emulating UIScrollView's UIScrollViewDelayedTouchesBeganGestureRecognizer.
// It catches all gestures incoming to UIView and delays them for 150ms
// (the same value used by UIScrollViewDelayedTouchesBeganGestureRecognizer)
-// If touch cancelation or end message is fired it fires delayed
+// If touch cancellation or end message is fired it fires delayed
// begin touch immediately as well as last touch signal
#import <UIKit/UIKit.h>
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index dcf9a46bf9..21456efde5 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -66,5 +66,5 @@ env.Zip(
zip_files,
ZIPROOT=zip_dir,
ZIPSUFFIX="${PROGSUFFIX}${ZIPSUFFIX}",
- ZIPCOMSTR="Archving $SOURCES as $TARGET",
+ ZIPCOMSTR="Archiving $SOURCES as $TARGET",
)
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index f029a91db0..c1607301d7 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -46,21 +46,21 @@ public:
static AudioDriverJavaScript *singleton;
- virtual const char *get_name() const;
+ const char *get_name() const override;
- virtual Error init();
- virtual void start();
+ Error init() override;
+ void start() override;
void resume();
- virtual float get_latency();
- virtual int get_mix_rate() const;
- virtual SpeakerMode get_speaker_mode() const;
- virtual void lock();
- virtual void unlock();
- virtual void finish();
+ float get_latency() override;
+ int get_mix_rate() const override;
+ SpeakerMode get_speaker_mode() const override;
+ void lock() override;
+ void unlock() override;
+ void finish() override;
void finish_async();
- virtual Error capture_start();
- virtual Error capture_stop();
+ Error capture_start() override;
+ Error capture_stop() override;
AudioDriverJavaScript();
};
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index 2fd1f45939..8dc33bdf64 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -75,7 +75,7 @@ bool DisplayServerJavaScript::check_size_force_redraw() {
if (last_width != canvas_width || last_height != canvas_height) {
last_width = canvas_width;
last_height = canvas_height;
- // Update the framebuffer size and for redraw.
+ // Update the framebuffer size for redraw.
emscripten_set_canvas_element_size(DisplayServerJavaScript::canvas_id, canvas_width, canvas_height);
return true;
}
@@ -892,15 +892,18 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
#define SET_EM_CALLBACK(target, ev, cb) \
result = emscripten_set_##ev##_callback(target, nullptr, true, &cb); \
EM_CHECK(ev)
+#define SET_EM_WINDOW_CALLBACK(ev, cb) \
+ result = emscripten_set_##ev##_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, NULL, false, &cb); \
+ EM_CHECK(ev)
#define SET_EM_CALLBACK_NOTARGET(ev, cb) \
result = emscripten_set_##ev##_callback(nullptr, true, &cb); \
EM_CHECK(ev)
// These callbacks from Emscripten's html5.h suffice to access most
// JavaScript APIs. For APIs that are not (sufficiently) exposed, EM_ASM
// is used below.
- SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mousemove, mousemove_callback)
SET_EM_CALLBACK(canvas_id, mousedown, mouse_button_callback)
- SET_EM_CALLBACK(EMSCRIPTEN_EVENT_TARGET_WINDOW, mouseup, mouse_button_callback)
+ SET_EM_WINDOW_CALLBACK(mousemove, mousemove_callback)
+ SET_EM_WINDOW_CALLBACK(mouseup, mouse_button_callback)
SET_EM_CALLBACK(canvas_id, wheel, wheel_callback)
SET_EM_CALLBACK(canvas_id, touchstart, touch_press_callback)
SET_EM_CALLBACK(canvas_id, touchmove, touchmove_callback)
@@ -918,27 +921,25 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
/* clang-format off */
EM_ASM_ARGS({
- Module.listeners = {};
+ // Bind native event listeners.
+ // Module.listeners, and Module.drop_handler are defined in native/utils.js
const canvas = Module['canvas'];
const send_window_event = cwrap('send_window_event', null, ['number']);
const notifications = arguments;
(['mouseover', 'mouseleave', 'focus', 'blur']).forEach(function(event, index) {
- Module.listeners[event] = send_window_event.bind(null, notifications[index]);
- canvas.addEventListener(event, Module.listeners[event]);
+ Module.listeners.add(canvas, event, send_window_event.bind(null, notifications[index]), true);
});
// Clipboard
const update_clipboard = cwrap('update_clipboard', null, ['string']);
- Module.listeners['paste'] = function(evt) {
+ Module.listeners.add(window, 'paste', function(evt) {
update_clipboard(evt.clipboardData.getData('text'));
- };
- window.addEventListener('paste', Module.listeners['paste'], false);
- Module.listeners['dragover'] = function(ev) {
+ }, false);
+ // Drag an drop
+ Module.listeners.add(canvas, 'dragover', function(ev) {
// Prevent default behavior (which would try to open the file(s))
ev.preventDefault();
- };
- Module.listeners['drop'] = Module.drop_handler; // Defined in native/utils.js
- canvas.addEventListener('dragover', Module.listeners['dragover'], false);
- canvas.addEventListener('drop', Module.listeners['drop'], false);
+ }, false);
+ Module.listeners.add(canvas, 'drop', Module.drop_handler, false);
},
WINDOW_EVENT_MOUSE_ENTER,
WINDOW_EVENT_MOUSE_EXIT,
@@ -952,14 +953,7 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive
DisplayServerJavaScript::~DisplayServerJavaScript() {
EM_ASM({
- Object.entries(Module.listeners).forEach(function(kv) {
- if (kv[0] == 'paste') {
- window.removeEventListener(kv[0], kv[1], true);
- } else {
- Module['canvas'].removeEventListener(kv[0], kv[1]);
- }
- });
- Module.listeners = {};
+ Module.listeners.clear();
});
//emscripten_webgl_commit_frame();
//emscripten_webgl_destroy_context(webgl_ctx);
@@ -1109,7 +1103,11 @@ Size2i DisplayServerJavaScript::window_get_min_size(WindowID p_window) const {
void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_window) {
last_width = p_size.x;
last_height = p_size.y;
- emscripten_set_canvas_element_size(canvas_id, p_size.x, p_size.y);
+ double scale = EM_ASM_DOUBLE({
+ return window.devicePixelRatio || 1;
+ });
+ emscripten_set_canvas_element_size(canvas_id, p_size.x * scale, p_size.y * scale);
+ emscripten_set_element_css_size(canvas_id, p_size.x, p_size.y);
}
Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const {
diff --git a/platform/javascript/display_server_javascript.h b/platform/javascript/display_server_javascript.h
index 6569ef1e42..d7116be36f 100644
--- a/platform/javascript/display_server_javascript.h
+++ b/platform/javascript/display_server_javascript.h
@@ -93,7 +93,7 @@ class DisplayServerJavaScript : public DisplayServer {
static void _dispatch_input_event(const Ref<InputEvent> &p_event);
protected:
- virtual int get_current_video_driver() const;
+ int get_current_video_driver() const;
public:
// Override return type to make writing static callbacks less tedious.
@@ -113,92 +113,92 @@ public:
bool check_size_force_redraw();
// from DisplayServer
- virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
- virtual bool has_feature(Feature p_feature) const;
- virtual String get_name() const;
+ void alert(const String &p_alert, const String &p_title = "ALERT!") override;
+ bool has_feature(Feature p_feature) const override;
+ String get_name() const override;
// cursor
- virtual void cursor_set_shape(CursorShape p_shape);
- virtual CursorShape cursor_get_shape() const;
- virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2());
+ void cursor_set_shape(CursorShape p_shape) override;
+ CursorShape cursor_get_shape() const override;
+ void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
// mouse
- virtual void mouse_set_mode(MouseMode p_mode);
- virtual MouseMode mouse_get_mode() const;
+ void mouse_set_mode(MouseMode p_mode) override;
+ MouseMode mouse_get_mode() const override;
// touch
- virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
// clipboard
- virtual void clipboard_set(const String &p_text);
- virtual String clipboard_get() const;
+ void clipboard_set(const String &p_text) override;
+ String clipboard_get() const override;
// screen
- virtual int get_screen_count() const;
- virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
- virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
- virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
- virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const;
+ int get_screen_count() const override;
+ Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+ Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+ Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
+ int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override;
// windows
- virtual Vector<DisplayServer::WindowID> get_window_list() const;
- virtual WindowID get_window_at_screen_position(const Point2i &p_position) const;
+ Vector<DisplayServer::WindowID> get_window_list() const override;
+ WindowID get_window_at_screen_position(const Point2i &p_position) const override;
- virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID);
- virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
+ void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override;
+ ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
- virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
- virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
+ void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
+ void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
+ void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
- virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);
+ int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
+ void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const;
- virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID);
+ Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override;
+ void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override;
- virtual void window_set_transient(WindowID p_window, WindowID p_parent);
+ void window_set_transient(WindowID p_window, WindowID p_parent) override;
- virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
- virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
+ Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
- virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const;
+ void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
+ Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID);
- virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const;
- virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const; // FIXME: Find clearer name for this.
+ void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override;
+ Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override;
+ Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID);
- virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const;
+ void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override;
+ WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const;
+ bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID);
- virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const;
+ void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override;
+ bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID);
- virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID);
+ void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override;
+ void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
- virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const;
+ bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
- virtual bool can_any_window_draw() const;
+ bool can_any_window_draw() const override;
// events
- virtual void process_events();
+ void process_events() override;
// icon
- virtual void set_icon(const Ref<Image> &p_icon);
+ void set_icon(const Ref<Image> &p_icon) override;
// others
- virtual bool get_swap_cancel_ok();
- virtual void swap_buffers();
+ bool get_swap_cancel_ok() override;
+ void swap_buffers() override;
static void register_javascript_driver();
DisplayServerJavaScript(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error);
diff --git a/platform/javascript/engine/engine.js b/platform/javascript/engine/engine.js
index 2630812814..adcd919a6b 100644
--- a/platform/javascript/engine/engine.js
+++ b/platform/javascript/engine/engine.js
@@ -33,6 +33,7 @@ Function('return this')()['Engine'] = (function() {
this.resizeCanvasOnStart = false;
this.onExecute = null;
this.onExit = null;
+ this.persistentPaths = [];
};
Engine.prototype.init = /** @param {string=} basePath */ function(basePath) {
@@ -56,12 +57,14 @@ Function('return this')()['Engine'] = (function() {
config['locateFile'] = Utils.createLocateRewrite(loadPath);
config['instantiateWasm'] = Utils.createInstantiatePromise(loadPromise);
Godot(config).then(function(module) {
- me.rtenv = module;
- if (unloadAfterInit) {
- unload();
- }
- resolve();
- config = null;
+ module['initFS'](me.persistentPaths).then(function(fs_err) {
+ me.rtenv = module;
+ if (unloadAfterInit) {
+ unload();
+ }
+ resolve();
+ config = null;
+ });
});
});
return initPromise;
@@ -220,6 +223,10 @@ Function('return this')()['Engine'] = (function() {
this.rtenv['copyToFS'](path, buffer);
};
+ Engine.prototype.setPersistentPaths = function(persistentPaths) {
+ this.persistentPaths = persistentPaths;
+ };
+
// Closure compiler exported engine methods.
/** @export */
Engine['isWebGLAvailable'] = Utils.isWebGLAvailable;
@@ -241,5 +248,6 @@ Function('return this')()['Engine'] = (function() {
Engine.prototype['setOnExecute'] = Engine.prototype.setOnExecute;
Engine.prototype['setOnExit'] = Engine.prototype.setOnExit;
Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
+ Engine.prototype['setPersistentPaths'] = Engine.prototype.setPersistentPaths;
return Engine;
})();
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 6a3a977cfb..230575abce 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -258,6 +258,7 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
current_line = current_line.replace("$GODOT_BASENAME", p_name);
current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name"));
current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
+ current_line = current_line.replace("$GODOT_FULL_WINDOW", p_preset->get("html/full_window_size") ? "true" : "false");
current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false");
current_line = current_line.replace("$GODOT_ARGS", flags_json);
str_export += current_line + "\n";
@@ -291,6 +292,7 @@ void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_op
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/full_window_size"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), ""));
}
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index a30d84a52c..01722c4bc8 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -39,6 +39,17 @@
static OS_JavaScript *os = nullptr;
static uint64_t target_ticks = 0;
+extern "C" EMSCRIPTEN_KEEPALIVE void _request_quit_callback(char *p_filev[], int p_filec) {
+ DisplayServerJavaScript *ds = DisplayServerJavaScript::get_singleton();
+ if (ds) {
+ Variant event = int(DisplayServer::WINDOW_EVENT_CLOSE_REQUEST);
+ Variant *eventp = &event;
+ Variant ret;
+ Callable::CallError ce;
+ ds->window_event_callback.call((const Variant **)&eventp, 1, ret, ce);
+ }
+}
+
void exit_callback() {
emscripten_cancel_main_loop(); // After this, we can exit!
Main::cleanup();
@@ -77,12 +88,27 @@ void main_loop_callback() {
/* clang-format on */
os->get_main_loop()->finish();
os->finalize_async(); // Will add all the async finish functions.
+ /* clang-format off */
EM_ASM({
Promise.all(Module.async_finish).then(function() {
Module.async_finish = [];
+ return new Promise(function(accept, reject) {
+ if (!Module.idbfs) {
+ accept();
+ return;
+ }
+ FS.syncfs(function(error) {
+ if (error) {
+ err('Failed to save IDB file system: ' + error.message);
+ }
+ accept();
+ });
+ });
+ }).then(function() {
ccall("cleanup_after_sync", null, []);
});
});
+ /* clang-format on */
}
}
@@ -90,31 +116,8 @@ extern "C" EMSCRIPTEN_KEEPALIVE void cleanup_after_sync() {
emscripten_set_main_loop(exit_callback, -1, false);
}
-extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) {
- String idbfs_err = String::utf8(p_idbfs_err);
- if (!idbfs_err.empty()) {
- print_line("IndexedDB not available: " + idbfs_err);
- }
- os->set_idb_available(idbfs_err.empty());
- // TODO: Check error return value.
- Main::setup2(); // Manual second phase.
- // Ease up compatibility.
- ResourceLoader::set_abort_on_missing_resources(false);
- Main::start();
- os->get_main_loop()->init();
- // Immediately run the first iteration.
- // We are inside an animation frame, we want to immediately draw on the newly setup canvas.
- main_loop_callback();
- emscripten_resume_main_loop();
-}
-
+/// When calling main, it is assumed FS is setup and synced.
int main(int argc, char *argv[]) {
- // Create and mount userfs immediately.
- EM_ASM({
- FS.mkdir('/userfs');
- FS.mount(IDBFS, {}, '/userfs');
- });
-
// Configure locale.
char locale_ptr[16];
/* clang-format off */
@@ -132,26 +135,30 @@ int main(int argc, char *argv[]) {
/* clang-format on */
os = new OS_JavaScript();
+ os->set_idb_available((bool)EM_ASM_INT({ return Module.idbfs }));
// We must override main when testing is enabled
TEST_MAIN_OVERRIDE
- Main::setup(argv[0], argc - 1, &argv[1], false);
- emscripten_set_main_loop(main_loop_callback, -1, false);
- emscripten_pause_main_loop(); // Will need to wait for FS sync.
+ Main::setup(argv[0], argc - 1, &argv[1]);
- // Sync from persistent state into memory and then
- // run the 'main_after_fs_sync' function.
+ // Ease up compatibility.
+ ResourceLoader::set_abort_on_missing_resources(false);
+
+ Main::start();
+ os->get_main_loop()->init();
+ // Expose method for requesting quit.
/* clang-format off */
EM_ASM({
- FS.syncfs(true, function(err) {
- requestAnimationFrame(function() {
- ccall('main_after_fs_sync', null, ['string'], [err ? err.message : ""]);
- });
- });
+ Module['request_quit'] = function() {
+ ccall("_request_quit_callback", null, []);
+ };
});
/* clang-format on */
+ emscripten_set_main_loop(main_loop_callback, -1, false);
+ // Immediately run the first iteration.
+ // We are inside an animation frame, we want to immediately draw on the newly setup canvas.
+ main_loop_callback();
return 0;
- // Continued async in main_after_fs_sync() from the syncfs() callback.
}
diff --git a/platform/javascript/native/utils.js b/platform/javascript/native/utils.js
index 95585d26ae..0b3698fd86 100644
--- a/platform/javascript/native/utils.js
+++ b/platform/javascript/native/utils.js
@@ -28,6 +28,38 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+Module['initFS'] = function(persistentPaths) {
+ FS.mkdir('/userfs');
+ FS.mount(IDBFS, {}, '/userfs');
+
+ function createRecursive(dir) {
+ try {
+ FS.stat(dir);
+ } catch (e) {
+ if (e.errno !== ERRNO_CODES.ENOENT) {
+ throw e;
+ }
+ FS.mkdirTree(dir);
+ }
+ }
+
+ persistentPaths.forEach(function(path) {
+ createRecursive(path);
+ FS.mount(IDBFS, {}, path);
+ });
+ return new Promise(function(resolve, reject) {
+ FS.syncfs(true, function(err) {
+ if (err) {
+ Module.idbfs = false;
+ console.log("IndexedDB not available: " + err.message);
+ } else {
+ Module.idbfs = true;
+ }
+ resolve(err);
+ });
+ });
+};
+
Module['copyToFS'] = function(path, buffer) {
var p = path.lastIndexOf("/");
var dir = "/";
@@ -37,7 +69,7 @@ Module['copyToFS'] = function(path, buffer) {
try {
FS.stat(dir);
} catch (e) {
- if (e.errno !== ERRNO_CODES.ENOENT) { // 'ENOENT', see https://github.com/emscripten-core/emscripten/blob/master/system/lib/libc/musl/arch/emscripten/bits/errno.h
+ if (e.errno !== ERRNO_CODES.ENOENT) {
throw e;
}
FS.mkdirTree(dir);
@@ -202,3 +234,44 @@ Module.drop_handler = (function() {
});
}
})();
+
+function EventHandlers() {
+ function Handler(target, event, method, capture) {
+ this.target = target;
+ this.event = event;
+ this.method = method;
+ this.capture = capture;
+ }
+
+ var listeners = [];
+
+ function has(target, event, method, capture) {
+ return listeners.findIndex(function(e) {
+ return e.target === target && e.event === event && e.method === method && e.capture == capture;
+ }) !== -1;
+ }
+
+ this.add = function(target, event, method, capture) {
+ if (has(target, event, method, capture)) {
+ return;
+ }
+ listeners.push(new Handler(target, event, method, capture));
+ target.addEventListener(event, method, capture);
+ };
+
+ this.remove = function(target, event, method, capture) {
+ if (!has(target, event, method, capture)) {
+ return;
+ }
+ target.removeEventListener(event, method, capture);
+ };
+
+ this.clear = function() {
+ listeners.forEach(function(h) {
+ h.target.removeEventListener(h.event, h.method, h.capture);
+ });
+ listeners.length = 0;
+ };
+}
+
+Module.listeners = new EventHandlers();
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index 1ff4304bcf..cf5751f384 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -46,24 +46,6 @@
#include <emscripten.h>
#include <stdlib.h>
-bool OS_JavaScript::has_touchscreen_ui_hint() const {
- /* clang-format off */
- return EM_ASM_INT_V(
- return 'ontouchstart' in window;
- );
- /* clang-format on */
-}
-
-// Audio
-
-int OS_JavaScript::get_audio_driver_count() const {
- return 1;
-}
-
-const char *OS_JavaScript::get_audio_driver_name(int p_driver) const {
- return "JavaScript";
-}
-
// Lifecycle
void OS_JavaScript::initialize() {
OS_Unix::initialize_core();
@@ -90,27 +72,24 @@ MainLoop *OS_JavaScript::get_main_loop() const {
return main_loop;
}
-void OS_JavaScript::main_loop_callback() {
- get_singleton()->main_loop_iterate();
+extern "C" EMSCRIPTEN_KEEPALIVE void _idb_synced() {
+ OS_JavaScript::get_singleton()->idb_is_syncing = false;
}
bool OS_JavaScript::main_loop_iterate() {
- if (is_userfs_persistent() && sync_wait_time >= 0) {
- int64_t current_time = get_ticks_msec();
- int64_t elapsed_time = current_time - last_sync_check_time;
- last_sync_check_time = current_time;
-
- sync_wait_time -= elapsed_time;
-
- if (sync_wait_time < 0) {
- /* clang-format off */
- EM_ASM(
- FS.syncfs(function(error) {
- if (error) { err('Failed to save IDB file system: ' + error.message); }
- });
- );
- /* clang-format on */
- }
+ if (is_userfs_persistent() && idb_needs_sync && !idb_is_syncing) {
+ idb_is_syncing = true;
+ idb_needs_sync = false;
+ /* clang-format off */
+ EM_ASM({
+ FS.syncfs(function(error) {
+ if (error) {
+ err('Failed to save IDB file system: ' + error.message);
+ }
+ ccall("_idb_synced", 'void', [], []);
+ });
+ });
+ /* clang-format on */
}
DisplayServer::get_singleton()->process_events();
@@ -201,10 +180,6 @@ String OS_JavaScript::get_name() const {
return "HTML5";
}
-bool OS_JavaScript::can_draw() const {
- return true; // Always?
-}
-
String OS_JavaScript::get_user_data_dir() const {
return "/userfs";
};
@@ -222,11 +197,17 @@ String OS_JavaScript::get_data_path() const {
}
void OS_JavaScript::file_access_close_callback(const String &p_file, int p_flags) {
- OS_JavaScript *os = get_singleton();
- if (os->is_userfs_persistent() && p_file.begins_with("/userfs") && p_flags & FileAccess::WRITE) {
- os->last_sync_check_time = OS::get_singleton()->get_ticks_msec();
- // Wait five seconds in case more files are about to be closed.
- os->sync_wait_time = 5000;
+ OS_JavaScript *os = OS_JavaScript::get_singleton();
+ if (!(os->is_userfs_persistent() && (p_flags & FileAccess::WRITE))) {
+ return; // FS persistence is not working or we are not writing.
+ }
+ bool is_file_persistent = p_file.begins_with("/userfs");
+#ifdef TOOLS_ENABLED
+ // Hack for editor persistence (can we track).
+ is_file_persistent = is_file_persistent || p_file.begins_with("/home/web_user/");
+#endif
+ if (is_file_persistent) {
+ os->idb_needs_sync = true;
}
}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 22234f9355..85551d708b 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -44,57 +44,52 @@ class OS_JavaScript : public OS_Unix {
bool finalizing = false;
bool idb_available = false;
- int64_t sync_wait_time = -1;
- int64_t last_sync_check_time = -1;
+ bool idb_needs_sync = false;
static void main_loop_callback();
static void file_access_close_callback(const String &p_file, int p_flags);
protected:
- virtual void initialize();
+ void initialize() override;
- virtual void set_main_loop(MainLoop *p_main_loop);
- virtual void delete_main_loop();
+ void set_main_loop(MainLoop *p_main_loop) override;
+ void delete_main_loop() override;
- virtual void finalize();
+ void finalize() override;
- virtual bool _check_internal_feature_support(const String &p_feature);
+ bool _check_internal_feature_support(const String &p_feature) override;
public:
+ bool idb_is_syncing = false;
+
// Override return type to make writing static callbacks less tedious.
static OS_JavaScript *get_singleton();
- virtual void initialize_joypads();
-
- virtual bool has_touchscreen_ui_hint() const;
-
- virtual int get_audio_driver_count() const;
- virtual const char *get_audio_driver_name(int p_driver) const;
+ void initialize_joypads() override;
- virtual MainLoop *get_main_loop() const;
+ MainLoop *get_main_loop() const override;
void finalize_async();
bool main_loop_iterate();
- virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr);
- virtual Error kill(const ProcessID &p_pid);
- virtual int get_process_id() const;
+ Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking = true, ProcessID *r_child_id = nullptr, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr) override;
+ Error kill(const ProcessID &p_pid) override;
+ int get_process_id() const override;
- String get_executable_path() const;
- virtual Error shell_open(String p_uri);
- virtual String get_name() const;
+ String get_executable_path() const override;
+ Error shell_open(String p_uri) override;
+ String get_name() const override;
// Override default OS implementation which would block the main thread with delay_usec.
// Implemented in javascript_main.cpp loop callback instead.
- virtual void add_frame_delay(bool p_can_draw) {}
- virtual bool can_draw() const;
+ void add_frame_delay(bool p_can_draw) override {}
- virtual String get_cache_path() const;
- virtual String get_config_path() const;
- virtual String get_data_path() const;
- virtual String get_user_data_dir() const;
+ String get_cache_path() const override;
+ String get_config_path() const override;
+ String get_data_path() const override;
+ String get_user_data_dir() const override;
void set_idb_available(bool p_idb_available);
- virtual bool is_userfs_persistent() const;
+ bool is_userfs_persistent() const override;
void resume_audio();
bool is_finalizing() { return finalizing; }
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 3eb4c44bc1..f5e2c72bbc 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -35,6 +35,11 @@ def can_build():
print("xinerama not found.. x11 disabled.")
return False
+ x11_error = os.system("pkg-config xext --modversion > /dev/null ")
+ if x11_error:
+ print("xext not found.. x11 disabled.")
+ return False
+
x11_error = os.system("pkg-config xrandr --modversion > /dev/null ")
if x11_error:
print("xrandr not found.. x11 disabled.")
@@ -194,6 +199,7 @@ def configure(env):
env.ParseConfig("pkg-config x11 --cflags --libs")
env.ParseConfig("pkg-config xcursor --cflags --libs")
env.ParseConfig("pkg-config xinerama --cflags --libs")
+ env.ParseConfig("pkg-config xext --cflags --libs")
env.ParseConfig("pkg-config xrandr --cflags --libs")
env.ParseConfig("pkg-config xrender --cflags --libs")
env.ParseConfig("pkg-config xi --cflags --libs")
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index fe9e253cc9..e3cf992302 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -50,6 +50,7 @@
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include <X11/extensions/Xinerama.h>
+#include <X11/extensions/shape.h>
// ICCCM
#define WM_NormalState 1L // window normal state
@@ -782,6 +783,38 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window
XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length());
}
+void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ const WindowData &wd = windows[p_window];
+
+ int event_base, error_base;
+ const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
+ if (ext_okay) {
+ Region region;
+ if (p_region.size() == 0) {
+ region = XCreateRegion();
+ XRectangle rect;
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = window_get_real_size(p_window).x;
+ rect.height = window_get_real_size(p_window).y;
+ XUnionRectWithRegion(&rect, region, region);
+ } else {
+ XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size());
+ for (int i = 0; i < p_region.size(); i++) {
+ points[i].x = p_region[i].x;
+ points[i].y = p_region[i].y;
+ }
+ region = XPolygonRegion(points, p_region.size(), EvenOddRule);
+ memfree(points);
+ }
+ XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
+ }
+}
+
void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -3542,7 +3575,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY);
if (!xrandr_handle) {
err = dlerror();
- fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+ // For some arcane reason, NetBSD now ships libXrandr.so.3 while the rest of the world has libXrandr.so.2...
+ // In case this happens for other X11 platforms in the future, let's give it a try too before failing.
+ xrandr_handle = dlopen("libXrandr.so.3", RTLD_LAZY);
+ if (!xrandr_handle) {
+ fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err);
+ }
} else {
XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor);
if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) {
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 57cee910a0..e894cf515c 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -291,6 +291,8 @@ public:
virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
+
virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index 764666681f..571ad03db0 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -31,7 +31,15 @@
#ifdef __linux__
#include <alloca.h>
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <stdlib.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#include <stdlib.h> // alloca
+// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms,
+// include NetBSD, use pthread_setname_np. NetBSD's version however requires
+// a different format, we handle this directly in thread_posix.
+#ifdef __NetBSD__
+#define PTHREAD_NETBSD_SET_NAME
+#else
#define PTHREAD_BSD_SET_NAME
#endif
+#endif
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index d8f3f81ff6..073d35008b 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -102,6 +102,8 @@ public:
id window_object;
id window_view;
+ Vector<Vector2> mpath;
+
#if defined(OPENGL_ENABLED)
ContextGL_OSX *context_gles2 = nullptr;
#endif
@@ -240,6 +242,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override;
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override;
+ virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override;
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override;
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index adfb47324e..49f0e7bfa3 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -33,6 +33,7 @@
#include "os_osx.h"
#include "core/io/marshalls.h"
+#include "core/math/geometry_2d.h"
#include "core/os/keyboard.h"
#include "main/main.h"
#include "scene/resources/texture.h"
@@ -2040,6 +2041,12 @@ void DisplayServerOSX::mouse_set_mode(MouseMode p_mode) {
CGDisplayHideCursor(kCGDirectMainDisplay);
}
CGAssociateMouseAndMouseCursorPosition(false);
+ WindowData &wd = windows[MAIN_WINDOW_ID];
+ const NSRect contentRect = [wd.window_view frame];
+ NSRect pointInWindowRect = NSMakeRect(contentRect.size.width / 2, contentRect.size.height / 2, 0, 0);
+ NSPoint pointOnScreen = [[wd.window_view window] convertRectToScreen:pointInWindowRect].origin;
+ CGPoint lMouseWarpPos = { pointOnScreen.x, CGDisplayBounds(CGMainDisplayID()).size.height - pointOnScreen.y };
+ CGWarpMouseCursorPosition(lMouseWarpPos);
} else if (p_mode == MOUSE_MODE_HIDDEN) {
if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) {
CGDisplayHideCursor(kCGDirectMainDisplay);
@@ -2404,6 +2411,15 @@ void DisplayServerOSX::window_set_title(const String &p_title, WindowID p_window
[wd.window_object setTitle:[NSString stringWithUTF8String:p_title.utf8().get_data()]];
}
+void DisplayServerOSX::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ WindowData &wd = windows[p_window];
+
+ wd.mpath = p_region;
+}
+
void DisplayServerOSX::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) {
_THREAD_SAFE_METHOD_
@@ -3356,6 +3372,26 @@ void DisplayServerOSX::process_events() {
Input::get_singleton()->flush_accumulated_events();
}
+ for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) {
+ WindowData &wd = E->get();
+ if (wd.mpath.size() > 0) {
+ const Vector2 mpos = _get_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
+ if (Geometry2D::is_point_in_polygon(mpos, wd.mpath)) {
+ if ([wd.window_object ignoresMouseEvents]) {
+ [wd.window_object setIgnoresMouseEvents:NO];
+ }
+ } else {
+ if (![wd.window_object ignoresMouseEvents]) {
+ [wd.window_object setIgnoresMouseEvents:YES];
+ }
+ }
+ } else {
+ if ([wd.window_object ignoresMouseEvents]) {
+ [wd.window_object setIgnoresMouseEvents:NO];
+ }
+ }
+ }
+
[autoreleasePool drain];
autoreleasePool = [[NSAutoreleasePool alloc] init];
}
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
index bdff93f02b..73136ec81b 100644
--- a/platform/server/platform_config.h
+++ b/platform/server/platform_config.h
@@ -31,10 +31,19 @@
#if defined(__linux__) || defined(__APPLE__)
#include <alloca.h>
#endif
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
-#include <stdlib.h>
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#include <stdlib.h> // alloca
+// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms,
+// include NetBSD, use pthread_setname_np. NetBSD's version however requires
+// a different format, we handle this directly in thread_posix.
+#ifdef __NetBSD__
+#define PTHREAD_NETBSD_SET_NAME
+#else
#define PTHREAD_BSD_SET_NAME
#endif
+#endif
+
#ifdef __APPLE__
#define PTHREAD_RENAME_SELF
#endif
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index daffe59f34..e3f86977a4 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -26,10 +26,10 @@ prog = env.add_program("#bin/godot", common_win + res_obj, PROGSUFFIX=env["PROGS
# Microsoft Visual Studio Project Generation
if env["vsproj"]:
- env.vs_srcs = env.vs_srcs + ["platform/windows/" + res_file]
- env.vs_srcs = env.vs_srcs + ["platform/windows/godot.natvis"]
+ env.vs_srcs += ["platform/windows/" + res_file]
+ env.vs_srcs += ["platform/windows/godot.natvis"]
for x in common_win:
- env.vs_srcs = env.vs_srcs + ["platform/windows/" + str(x)]
+ env.vs_srcs += ["platform/windows/" + str(x)]
if not os.getenv("VCINSTALLDIR"):
if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index c380142c72..6b503c1561 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -439,7 +439,7 @@ def configure_mingw(env):
else:
env.Append(LIBS=["cfgmgr32"])
- ## TODO !!! Reenable when OpenGLES Rendering Device is implemented !!!
+ ## TODO !!! Re-enable when OpenGLES Rendering Device is implemented !!!
# env.Append(CPPDEFINES=['OPENGL_ENABLED'])
env.Append(LIBS=["opengl32"])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 7f4669b3b2..dfbb734ee4 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -29,7 +29,9 @@
/*************************************************************************/
#include "display_server_windows.h"
+
#include "core/io/marshalls.h"
+#include "core/math/geometry_2d.h"
#include "main/main.h"
#include "os_windows.h"
#include "scene/resources/texture.h"
@@ -597,6 +599,36 @@ void DisplayServerWindows::window_set_title(const String &p_title, WindowID p_wi
SetWindowTextW(windows[p_window].hWnd, (LPCWSTR)(p_title.utf16().get_data()));
}
+void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) {
+ _THREAD_SAFE_METHOD_
+
+ ERR_FAIL_COND(!windows.has(p_window));
+ windows[p_window].mpath = p_region;
+ _update_window_mouse_passthrough(p_window);
+}
+
+void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
+ if (windows[p_window].mpath.size() == 0) {
+ SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
+ } else {
+ POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size());
+ for (int i = 0; i < windows[p_window].mpath.size(); i++) {
+ if (windows[p_window].borderless) {
+ points[i].x = windows[p_window].mpath[i].x;
+ points[i].y = windows[p_window].mpath[i].y;
+ } else {
+ points[i].x = windows[p_window].mpath[i].x + GetSystemMetrics(SM_CXSIZEFRAME);
+ points[i].y = windows[p_window].mpath[i].y + GetSystemMetrics(SM_CYSIZEFRAME) + GetSystemMetrics(SM_CYCAPTION);
+ }
+ }
+
+ HRGN region = CreatePolygonRgn(points, windows[p_window].mpath.size(), ALTERNATE);
+ SetWindowRgn(windows[p_window].hWnd, region, TRUE);
+ DeleteObject(region);
+ memfree(points);
+ }
+}
+
int DisplayServerWindows::window_get_current_screen(WindowID p_window) const {
_THREAD_SAFE_METHOD_
@@ -1010,6 +1042,7 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
case WINDOW_FLAG_BORDERLESS: {
wd.borderless = p_enabled;
_update_window_style(p_window);
+ _update_window_mouse_passthrough(p_window);
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID && p_enabled, "Transient windows can't become on top");
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 7bd93a7086..0fca2589ae 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -323,6 +323,8 @@ private:
HWND hWnd;
//layered window
+ Vector<Vector2> mpath;
+
bool preserve_window_size = false;
bool pre_fs_valid = false;
RECT pre_fs_rect;
@@ -416,6 +418,7 @@ private:
void _touch_event(WindowID p_window, bool p_pressed, float p_x, float p_y, int idx);
void _update_window_style(WindowID p_window, bool p_repaint = true, bool p_maximized = false);
+ void _update_window_mouse_passthrough(WindowID p_window);
void _update_real_mouse_position(WindowID p_window);
@@ -477,6 +480,7 @@ public:
virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID);
virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID);
+ virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID);
virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const;
virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID);