summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/build.gradle.template1
-rw-r--r--platform/android/detect.py19
-rw-r--r--platform/android/export/export.cpp28
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java15
-rw-r--r--platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java11
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java14
-rw-r--r--platform/android/java_glue.cpp2
-rw-r--r--platform/android/os_android.cpp11
-rw-r--r--platform/android/os_android.h2
-rw-r--r--platform/javascript/SCsub11
-rw-r--r--platform/javascript/detect.py5
-rw-r--r--platform/javascript/export/export.cpp10
-rw-r--r--platform/javascript/os_javascript.cpp38
-rw-r--r--platform/javascript/os_javascript.h3
-rw-r--r--platform/osx/SCsub3
-rw-r--r--platform/osx/detect.py3
-rw-r--r--platform/osx/godot_main_osx.mm11
-rw-r--r--platform/osx/os_osx.h19
-rw-r--r--platform/osx/os_osx.mm246
-rw-r--r--platform/server/detect.py13
-rw-r--r--platform/windows/SCsub2
-rw-r--r--platform/windows/detect.py5
-rw-r--r--platform/windows/os_windows.cpp86
-rw-r--r--platform/windows/os_windows.h10
-rw-r--r--platform/x11/SCsub2
-rw-r--r--platform/x11/detect.py17
-rw-r--r--platform/x11/os_x11.cpp134
-rw-r--r--platform/x11/os_x11.h8
29 files changed, 583 insertions, 148 deletions
diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template
index 89189ef1a0..7269e658b4 100644
--- a/platform/android/build.gradle.template
+++ b/platform/android/build.gradle.template
@@ -15,6 +15,7 @@ allprojects {
repositories {
jcenter()
mavenCentral()
+ google()
$$GRADLE_REPOSITORY_URLS$$
}
}
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 892b1b6a85..971368db17 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -14,10 +14,13 @@ def get_name():
def can_build():
-
return ("ANDROID_NDK_ROOT" in os.environ)
+def get_platform(platform):
+ return int(platform.split("-")[1])
+
+
def get_opts():
from SCons.Variables import BoolVariable, EnumVariable
@@ -124,6 +127,9 @@ def configure(env):
else:
env.extra_suffix = ".armv7" + env.extra_suffix
elif env["android_arch"] == "arm64v8":
+ if get_platform(env["ndk_platform"]) < 21:
+ print("WARNING: android_arch=arm64v8 is not supported by ndk_platform lower than andorid-21; setting ndk_platform=android-21")
+ env["ndk_platform"] = "android-21"
env['ARCH'] = 'arch-arm64'
target_subpath = "aarch64-linux-android-4.9"
abi_subpath = "aarch64-linux-android"
@@ -160,12 +166,13 @@ def configure(env):
elif (sys.platform.startswith('win')):
if (platform.machine().endswith('64')):
host_subpath = "windows-x86_64"
- if env["android_arch"] == "arm64v8":
- mt_link = False
else:
mt_link = False
host_subpath = "windows"
+ if env["android_arch"] == "arm64v8":
+ mt_link = False
+
compiler_path = env["ANDROID_NDK_ROOT"] + "/toolchains/llvm/prebuilt/" + host_subpath + "/bin"
gcc_toolchain_path = env["ANDROID_NDK_ROOT"] + "/toolchains/" + target_subpath + "/prebuilt/" + host_subpath
tools_path = gcc_toolchain_path + "/" + abi_subpath + "/bin"
@@ -199,7 +206,7 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include"])
env.Append(CPPFLAGS=["-isystem", sysroot + "/usr/include/" + abi_subpath])
# For unified headers this define has to be set manually
- env.Append(CPPFLAGS=["-D__ANDROID_API__=" + str(int(env['ndk_platform'].split("-")[1]))])
+ env.Append(CPPFLAGS=["-D__ANDROID_API__=" + str(get_platform(env['ndk_platform']))])
else:
print("Using NDK deprecated headers")
env.Append(CPPFLAGS=["-isystem", lib_sysroot + "/usr/include"])
@@ -254,10 +261,10 @@ def configure(env):
env.Append(LINKFLAGS=target_opts)
env.Append(LINKFLAGS=common_opts)
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/arm-linux-androideabi-4.9/prebuilt/' +
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] + '/toolchains/' + target_subpath + '/prebuilt/' +
host_subpath + '/lib/gcc/' + abi_subpath + '/4.9.x'])
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"] +
- '/toolchains/arm-linux-androideabi-4.9/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib'])
+ '/toolchains/' + target_subpath + '/prebuilt/' + host_subpath + '/' + abi_subpath + '/lib'])
env.Append(CPPPATH=['#platform/android'])
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL', '-DMPC_FIXED_POINT'])
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index b26d2a3aa4..2a61f8d873 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -552,6 +552,10 @@ class EditorExportAndroid : public EditorExportPlatform {
return OK;
}
+ static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector<uint8_t> &p_data, int p_file, int p_total) {
+ return OK;
+ }
+
void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) {
// Leaving the unused types commented because looking these constants up
@@ -1504,6 +1508,10 @@ public:
cl.push_back(passwd);
}*/
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so);
} else {
//all files
@@ -1531,17 +1539,17 @@ public:
err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so);
}
+ }
- if (!err) {
- APKExportData ed;
- ed.ep = &ep;
- ed.apk = unaligned_apk;
- for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) {
- String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges();
- if (icon_path != "" && icon_path.ends_with(".png") && FileAccess::exists(icon_path)) {
- Vector<uint8_t> data = FileAccess::get_file_as_array(icon_path);
- store_in_apk(&ed, launcher_icons[i].export_path, data);
- }
+ if (!err) {
+ APKExportData ed;
+ ed.ep = &ep;
+ ed.apk = unaligned_apk;
+ for (int i = 0; i < sizeof(launcher_icons) / sizeof(launcher_icons[0]); ++i) {
+ String icon_path = String(p_preset->get(launcher_icons[i].option_id)).strip_edges();
+ if (icon_path != "" && icon_path.ends_with(".png") && FileAccess::exists(icon_path)) {
+ Vector<uint8_t> data = FileAccess::get_file_as_array(icon_path);
+ store_in_apk(&ed, launcher_icons[i].export_path, data);
}
}
}
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
index b5b0afb9e0..0d14211bd0 100644
--- a/platform/android/java/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -404,7 +404,7 @@ public class Godot extends Activity implements SensorEventListener, IDownloaderC
new_cmdline = new String[2];
}
- new_cmdline[cll] = "--main_pack";
+ new_cmdline[cll] = "--main-pack";
new_cmdline[cll + 1] = expansion_pack_path;
command_line = new_cmdline;
}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
index 6b7f7a283e..d72c590378 100644
--- a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
+++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
@@ -67,7 +67,7 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
public GodotPaymentV3(Activity p_activity) {
- registerClass("GodotPayments", new String[] { "purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails" });
+ registerClass("GodotPayments", new String[] { "purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume", "querySkuDetails", "isConnected" });
activity = (Godot)p_activity;
mPaymentManager = activity.getPaymentsManager();
mPaymentManager.setBaseSingleton(this);
@@ -164,6 +164,19 @@ public class GodotPaymentV3 extends Godot.SingletonBase {
GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[] { receipt, signature, sku });
}
+ public void callbackDisconnected() {
+ GodotLib.calldeferred(purchaseCallbackId, "iap_disconnected", new Object[]{});
+ }
+
+ public void callbackConnected() {
+ GodotLib.calldeferred(purchaseCallbackId, "iap_connected", new Object[]{});
+ }
+
+ // true if connected, false otherwise
+ public boolean isConnected() {
+ return mPaymentManager.isConnected();
+ }
+
// consume item automatically after purchase. default is true.
public void setAutoConsume(boolean autoConsume) {
mPaymentManager.setAutoConsume(autoConsume);
diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
index 1102ab7450..5d13f17ffb 100644
--- a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
+++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -103,13 +103,16 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene
public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) {
//Log.d(TAG, "onTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",before: " + before);
+ final int[] newChars = new int[count];
+ for (int i = start; i < start + count; ++i) {
+ newChars[i - start] = pCharSequence.charAt(i);
+ }
mView.queueEvent(new Runnable() {
@Override
public void run() {
- for (int i = start; i < start + count; ++i) {
- final int ch = pCharSequence.charAt(i);
- GodotLib.key(0, ch, true);
- GodotLib.key(0, ch, false);
+ for (int i = 0; i < count; ++i) {
+ GodotLib.key(0, newChars[i], true);
+ GodotLib.key(0, newChars[i], false);
}
}
});
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
index da6d66ae88..441a311358 100644
--- a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
+++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
@@ -93,11 +93,21 @@ public class PaymentsManager {
@Override
public void onServiceDisconnected(ComponentName name) {
mService = null;
+
+ // At this stage, godotPaymentV3 might not have been initialized yet.
+ if (godotPaymentV3 != null) {
+ godotPaymentV3.callbackDisconnected();
+ }
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = IInAppBillingService.Stub.asInterface(service);
+
+ // At this stage, godotPaymentV3 might not have been initialized yet.
+ if (godotPaymentV3 != null) {
+ godotPaymentV3.callbackConnected();
+ }
}
};
@@ -123,6 +133,10 @@ public class PaymentsManager {
.purchase(sku, transactionId);
}
+ public boolean isConnected() {
+ return mService != null;
+ }
+
public void consumeUnconsumedPurchases() {
new ReleaseAllConsumablesTask(mService, activity) {
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 4e9e4f6260..2d81d79bf1 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -926,7 +926,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
} else {
//__android_log_print(ANDROID_LOG_INFO,"godot","cmdline arg %i is: %s\n",i,rawString);
- if (strcmp(rawString, "-main_pack") == 0)
+ if (strcmp(rawString, "--main-pack") == 0)
use_apk_expansion = true;
}
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 23811f963a..67ce796279 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -48,6 +48,8 @@
#include "file_access_jandroid.h"
#endif
+#include <dlfcn.h>
+
class AndroidLogger : public Logger {
public:
virtual void logv(const char *p_format, va_list p_list, bool p_err) {
@@ -173,6 +175,15 @@ void OS_Android::alert(const String &p_alert, const String &p_title) {
alert_func(p_alert, p_title);
}
+Error OS_Android::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path) {
+ p_library_handle = dlopen(p_path.utf8().get_data(), RTLD_NOW);
+ if (!p_library_handle) {
+ ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + dlerror());
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+ return OK;
+}
+
void OS_Android::set_mouse_show(bool p_show) {
//android has no mouse...
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 7ace7b5200..12181b3688 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -159,6 +159,8 @@ public:
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");
+ virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false);
+
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
virtual bool is_mouse_grab_enabled() const;
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index 05992ebac8..66a8a8d93c 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -23,6 +23,7 @@ env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_main_after_fs_sync'
target_dir = env.Dir("#bin")
build = env.add_program(['#bin/godot', target_dir.File('godot' + env['PROGSUFFIX'] + '.wasm')], javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js');
+js, wasm = build
js_libraries = []
js_libraries.append(env.File('http_request.js'))
@@ -30,12 +31,10 @@ for lib in js_libraries:
env.Append(LINKFLAGS=['--js-library', lib.path])
env.Depends(build, js_libraries)
-prejs = env.File('pre.js')
-postjs = env.File('engine.js')
-env.Append(LINKFLAGS=['--pre-js', prejs.path])
-env.Append(LINKFLAGS=['--post-js', postjs.path])
-env.Depends(build, [prejs, postjs])
+wrapper_start = env.File('pre.js')
+wrapper_end = env.File('engine.js')
+js_final = env.Textfile('#bin/godot', [wrapper_start, js, wrapper_end], TEXTFILESUFFIX=env['PROGSUFFIX'] + '.wrapped.js')
zip_dir = target_dir.Dir('.javascript_zip')
-zip_files = env.InstallAs([zip_dir.File('godot.js'), zip_dir.File('godot.wasm'), zip_dir.File('godot.html')], build + ['#misc/dist/html/default.html'])
+zip_files = env.InstallAs([zip_dir.File('godot.js'), zip_dir.File('godot.wasm'), zip_dir.File('godot.html')], [js_final, wasm, '#misc/dist/html/default.html'])
Zip('#bin/godot', zip_files, ZIPSUFFIX=env['PROGSUFFIX'] + env['ZIPSUFFIX'], ZIPROOT=zip_dir, ZIPCOMSTR="Archving $SOURCES as $TARGET")
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 8c7a904bca..7e6a1518ed 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -28,6 +28,11 @@ def get_flags():
return [
('tools', False),
('module_theora_enabled', False),
+ # Disabling the mbedtls module reduces file size.
+ # The module has little use due to the limited networking functionality
+ # in this platform. For the available networking methods, the browser
+ # manages TLS.
+ ('module_mbedtls_enabled', False),
]
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 61f55beb4e..d81aa25c32 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -71,7 +71,7 @@ public:
virtual void get_platform_features(List<String> *r_features) {
r_features->push_back("web");
- r_features->push_back("JavaScript");
+ r_features->push_back(get_os_name());
}
EditorExportPlatformJavaScript();
@@ -114,9 +114,9 @@ void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportP
void EditorExportPlatformJavaScript::get_export_options(List<ExportOption> *r_options) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), false));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), true));
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/etc2"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_GLOBAL_FILE, "html"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "zip"), ""));
@@ -130,7 +130,7 @@ String EditorExportPlatformJavaScript::get_name() const {
String EditorExportPlatformJavaScript::get_os_name() const {
- return "JavaScript";
+ return "HTML5";
}
Ref<Texture> EditorExportPlatformJavaScript::get_logo() const {
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index b10ef821dd..e226ab6332 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -81,12 +81,6 @@ void OS_JavaScript::initialize_core() {
FileAccess::make_default<FileAccessBufferedFA<FileAccessUnix> >(FileAccess::ACCESS_RESOURCES);
}
-void OS_JavaScript::set_opengl_extensions(const char *p_gl_extensions) {
-
- ERR_FAIL_COND(!p_gl_extensions);
- gl_extensions = p_gl_extensions;
-}
-
static EM_BOOL _browser_resize_callback(int event_type, const EmscriptenUiEvent *ui_event, void *user_data) {
ERR_FAIL_COND_V(event_type != EMSCRIPTEN_EVENT_RESIZE, false);
@@ -436,16 +430,11 @@ Error OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver,
// can't fulfil fullscreen request due to browser security
video_mode.fullscreen = false;
/* clang-format off */
- bool resize_canvas_on_start = EM_ASM_INT_V(
- return Module.resizeCanvasOnStart;
- );
- /* clang-format on */
- if (resize_canvas_on_start) {
+ if (EM_ASM_INT_V({ return Module.resizeCanvasOnStart })) {
+ /* clang-format on */
set_window_size(Size2(video_mode.width, video_mode.height));
} else {
- Size2 canvas_size = get_window_size();
- video_mode.width = canvas_size.width;
- video_mode.height = canvas_size.height;
+ set_window_size(get_window_size());
}
char locale_ptr[16];
@@ -975,7 +964,25 @@ int OS_JavaScript::get_power_percent_left() {
bool OS_JavaScript::_check_internal_feature_support(const String &p_feature) {
- return p_feature == "web" || p_feature == "s3tc"; // TODO check for these features really being available
+ if (p_feature == "HTML5" || p_feature == "web")
+ return true;
+
+#ifdef JAVASCRIPT_EVAL_ENABLED
+ if (p_feature == "JavaScript")
+ return true;
+#endif
+
+ EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_get_current_context();
+ // all extensions are already automatically enabled, this function allows
+ // checking WebGL extension support without inline JavaScript
+ if (p_feature == "s3tc" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_s3tc_srgb"))
+ return true;
+ if (p_feature == "etc" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc1"))
+ return true;
+ if (p_feature == "etc2" && emscripten_webgl_enable_extension(ctx, "WEBGL_compressed_texture_etc"))
+ return true;
+
+ return false;
}
void OS_JavaScript::set_idbfs_available(bool p_idbfs_available) {
@@ -992,7 +999,6 @@ OS_JavaScript::OS_JavaScript(const char *p_execpath, GetUserDataDirFunc p_get_us
set_cmdline(p_execpath, get_cmdline_args());
main_loop = NULL;
- gl_extensions = NULL;
window_maximized = false;
soft_fs_enabled = false;
canvas_size_adjustment_requested = false;
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index ce4763ab64..f0ba9422e8 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -52,7 +52,6 @@ class OS_JavaScript : public OS_Unix {
VisualServer *visual_server;
AudioDriverJavaScript audio_driver_javascript;
- const char *gl_extensions;
InputDefault *input;
Vector2 windowed_size;
@@ -139,8 +138,6 @@ public:
virtual bool has_touchscreen_ui_hint() const;
- void set_opengl_extensions(const char *p_gl_extensions);
-
virtual Error shell_open(String p_uri);
virtual String get_user_data_dir() const;
String get_executable_path() const;
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index 029e3d808c..5efe2d0b22 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -10,6 +10,7 @@ def make_debug(target, source, env):
os.system(mpprefix + '/libexec/llvm-' + mpclangver + '/bin/llvm-dsymutil %s -o %s.dSYM' % (target[0], target[0]))
else:
os.system('dsymutil %s -o %s.dSYM' % (target[0], target[0]))
+ os.system('strip -u -r %s' % (target[0]))
files = [
'crash_handler_osx.mm',
@@ -23,6 +24,6 @@ files = [
prog = env.add_program('#bin/godot', files)
-if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
+if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
env.AddPostAction(prog, make_debug)
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index bb601abd40..5f33100e42 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -19,11 +19,12 @@ def can_build():
def get_opts():
- from SCons.Variables import EnumVariable
+ from SCons.Variables import BoolVariable, EnumVariable
return [
('osxcross_sdk', 'OSXCross SDK version', 'darwin14'),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('separate_debug_symbols', 'Create a separate file with the debug symbols', False),
]
diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm
index 9d1a5566c9..6ccbaf896b 100644
--- a/platform/osx/godot_main_osx.mm
+++ b/platform/osx/godot_main_osx.mm
@@ -82,8 +82,17 @@ int main(int argc, char **argv) {
#endif
OS_OSX os;
+ Error err;
+
+ if (os.open_with_filename != "") {
+ char *argv_c = (char *)malloc(os.open_with_filename.utf8().size());
+ memcpy(argv_c, os.open_with_filename.utf8().get_data(), os.open_with_filename.utf8().size());
+ err = Main::setup(argv[0], 1, &argv_c);
+ free(argv_c);
+ } else {
+ err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]);
+ }
- Error err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]);
if (err != OK)
return 255;
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 3648d41604..aa8db8f300 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -52,6 +52,17 @@
class OS_OSX : public OS_Unix {
public:
+ struct KeyEvent {
+ unsigned int osx_state;
+ bool pressed;
+ bool echo;
+ uint32_t scancode;
+ uint32_t unicode;
+ };
+
+ Vector<KeyEvent> key_event_buffer;
+ int key_event_pos;
+
bool force_quit;
// rasterizer seems to no longer be given to visual server, its using GLES3 directly?
//Rasterizer *rasterizer;
@@ -72,6 +83,7 @@ public:
CGEventSourceRef eventSource;
void process_events();
+ void process_key_events();
void *framework;
// pthread_key_t current;
@@ -99,6 +111,8 @@ public:
Size2 window_size;
Rect2 restore_rect;
+ String open_with_filename;
+
Point2 im_position;
ImeCallback im_callback;
void *im_target;
@@ -153,6 +167,7 @@ public:
virtual void set_window_title(const String &p_title);
virtual Size2 get_window_size() const;
+ virtual Size2 get_real_window_size() const;
virtual void set_icon(const Ref<Image> &p_icon);
@@ -207,6 +222,8 @@ public:
virtual bool is_window_minimized() const;
virtual void set_window_maximized(bool p_enabled);
virtual bool is_window_maximized() const;
+ virtual void set_window_always_on_top(bool p_enabled);
+ virtual bool is_window_always_on_top() const;
virtual void request_attention();
virtual String get_joy_guid(int p_device) const;
@@ -215,6 +232,8 @@ public:
virtual void set_ime_position(const Point2 &p_pos);
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp);
+ virtual String get_unique_id() const;
+
virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 939f75859c..4c459772aa 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -88,6 +88,15 @@ static void get_key_modifier_state(unsigned int p_osx_state, Ref<InputEventWithM
state->set_metakey((p_osx_state & NSEventModifierFlagCommand));
}
+static void push_to_key_event_buffer(const OS_OSX::KeyEvent &p_event) {
+
+ Vector<OS_OSX::KeyEvent> &buffer = OS_OSX::singleton->key_event_buffer;
+ if (OS_OSX::singleton->key_event_pos >= buffer.size()) {
+ buffer.resize(1 + OS_OSX::singleton->key_event_pos);
+ }
+ buffer[OS_OSX::singleton->key_event_pos++] = p_event;
+}
+
static int mouse_x = 0;
static int mouse_y = 0;
static int prev_mouse_x = 0;
@@ -144,6 +153,13 @@ static Vector2 get_mouse_pos(NSEvent *event) {
@implementation GodotApplicationDelegate
+- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
+ // Note: called before main loop init!
+ char *utfs = strdup([filename UTF8String]);
+ OS_OSX::singleton->open_with_filename.parse_utf8(utfs);
+ return YES;
+}
+
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {
if (OS_OSX::singleton->get_main_loop())
OS_OSX::singleton->get_main_loop()->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
@@ -407,13 +423,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange {
NSEvent *event = [NSApp currentEvent];
- Ref<InputEventKey> k;
- k.instance();
-
- get_key_modifier_state([event modifierFlags], k);
- k->set_pressed(true);
- k->set_echo(false);
- k->set_scancode(0);
NSString *characters;
if ([aString isKindOfClass:[NSAttributedString class]]) {
@@ -438,8 +447,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
if ((codepoint & 0xFF00) == 0xF700)
continue;
- k->set_unicode(codepoint);
- OS_OSX::singleton->push_input(k);
+ OS_OSX::KeyEvent ke;
+
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = false;
+ ke.scancode = 0;
+ ke.unicode = codepoint;
+
+ push_to_key_event_buffer(ke);
}
[self cancelComposition];
}
@@ -788,80 +804,87 @@ static int translateKey(unsigned int key) {
- (void)keyDown:(NSEvent *)event {
- Ref<InputEventKey> k;
- k.instance();
-
- get_key_modifier_state([event modifierFlags], k);
- k->set_pressed(true);
- k->set_scancode(latin_keyboard_keycode_convert(translateKey([event keyCode])));
- k->set_echo([event isARepeat]);
+ //disable raw input in IME mode
+ if (!imeMode) {
+ OS_OSX::KeyEvent ke;
- NSString *characters = [event characters];
- NSUInteger i, length = [characters length];
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = true;
+ ke.echo = [event isARepeat];
+ ke.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
+ ke.unicode = 0;
- //disable raw input in IME mode
- if (!imeMode)
- OS_OSX::singleton->push_input(k);
+ push_to_key_event_buffer(ke);
+ }
if ((OS_OSX::singleton->im_position.x != 0) && (OS_OSX::singleton->im_position.y != 0))
[self interpretKeyEvents:[NSArray arrayWithObject:event]];
}
- (void)flagsChanged:(NSEvent *)event {
- Ref<InputEventKey> k;
- k.instance();
- int key = [event keyCode];
- int mod = [event modifierFlags];
+ if (!imeMode) {
+ OS_OSX::KeyEvent ke;
- if (key == 0x36 || key == 0x37) {
- if (mod & NSEventModifierFlagCommand) {
- mod &= ~NSEventModifierFlagCommand;
- k->set_pressed(true);
- } else {
- k->set_pressed(false);
- }
- } else if (key == 0x38 || key == 0x3c) {
- if (mod & NSEventModifierFlagShift) {
- mod &= ~NSEventModifierFlagShift;
- k->set_pressed(true);
- } else {
- k->set_pressed(false);
- }
- } else if (key == 0x3a || key == 0x3d) {
- if (mod & NSEventModifierFlagOption) {
- mod &= ~NSEventModifierFlagOption;
- k->set_pressed(true);
- } else {
- k->set_pressed(false);
- }
- } else if (key == 0x3b || key == 0x3e) {
- if (mod & NSEventModifierFlagControl) {
- mod &= ~NSEventModifierFlagControl;
- k->set_pressed(true);
+ ke.echo = false;
+
+ int key = [event keyCode];
+ int mod = [event modifierFlags];
+
+ if (key == 0x36 || key == 0x37) {
+ if (mod & NSEventModifierFlagCommand) {
+ mod &= ~NSEventModifierFlagCommand;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x38 || key == 0x3c) {
+ if (mod & NSEventModifierFlagShift) {
+ mod &= ~NSEventModifierFlagShift;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3a || key == 0x3d) {
+ if (mod & NSEventModifierFlagOption) {
+ mod &= ~NSEventModifierFlagOption;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
+ } else if (key == 0x3b || key == 0x3e) {
+ if (mod & NSEventModifierFlagControl) {
+ mod &= ~NSEventModifierFlagControl;
+ ke.pressed = true;
+ } else {
+ ke.pressed = false;
+ }
} else {
- k->set_pressed(false);
+ return;
}
- } else {
- return;
- }
- get_key_modifier_state(mod, k);
- k->set_scancode(latin_keyboard_keycode_convert(translateKey(key)));
+ ke.osx_state = mod;
+ ke.scancode = latin_keyboard_keycode_convert(translateKey(key));
+ ke.unicode = 0;
- OS_OSX::singleton->push_input(k);
+ push_to_key_event_buffer(ke);
+ }
}
- (void)keyUp:(NSEvent *)event {
- Ref<InputEventKey> k;
- k.instance();
+ if (!imeMode) {
+
+ OS_OSX::KeyEvent ke;
- get_key_modifier_state([event modifierFlags], k);
- k->set_pressed(false);
- k->set_scancode(latin_keyboard_keycode_convert(translateKey([event keyCode])));
+ ke.osx_state = [event modifierFlags];
+ ke.pressed = false;
+ ke.echo = false;
+ ke.scancode = latin_keyboard_keycode_convert(translateKey([event keyCode]));
+ ke.unicode = 0;
- OS_OSX::singleton->push_input(k);
+ push_to_key_event_buffer(ke);
+ }
}
inline void sendScrollEvent(int button, double factor, int modifierFlags) {
@@ -940,6 +963,30 @@ void OS_OSX::set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_
}
}
+String OS_OSX::get_unique_id() const {
+
+ static String serial_number;
+
+ if (serial_number.empty()) {
+ io_service_t platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
+ CFStringRef serialNumberAsCFString = NULL;
+ if (platformExpert) {
+ serialNumberAsCFString = (CFStringRef)IORegistryEntryCreateCFProperty(platformExpert, CFSTR(kIOPlatformSerialNumberKey), kCFAllocatorDefault, 0);
+ IOObjectRelease(platformExpert);
+ }
+
+ NSString *serialNumberAsNSString = nil;
+ if (serialNumberAsCFString) {
+ serialNumberAsNSString = [NSString stringWithString:(NSString *)serialNumberAsCFString];
+ CFRelease(serialNumberAsCFString);
+ }
+
+ serial_number = [serialNumberAsNSString UTF8String];
+ }
+
+ return serial_number;
+}
+
void OS_OSX::set_ime_position(const Point2 &p_pos) {
im_position = p_pos;
}
@@ -1822,6 +1869,12 @@ Size2 OS_OSX::get_window_size() const {
return window_size;
};
+Size2 OS_OSX::get_real_window_size() const {
+
+ NSRect frame = [window_object frame];
+ return Size2(frame.size.width, frame.size.height);
+}
+
void OS_OSX::set_window_size(const Size2 p_size) {
Size2 size = p_size;
@@ -1913,6 +1966,20 @@ void OS_OSX::move_window_to_foreground() {
[window_object orderFrontRegardless];
}
+void OS_OSX::set_window_always_on_top(bool p_enabled) {
+ if (is_window_always_on_top() == p_enabled)
+ return;
+
+ if (p_enabled)
+ [window_object setLevel:NSFloatingWindowLevel];
+ else
+ [window_object setLevel:NSNormalWindowLevel];
+}
+
+bool OS_OSX::is_window_always_on_top() const {
+ return [window_object level] == NSFloatingWindowLevel;
+}
+
void OS_OSX::request_attention() {
[NSApp requestUserAttention:NSCriticalRequest];
@@ -2060,11 +2127,49 @@ void OS_OSX::process_events() {
[NSApp sendEvent:event];
}
+ process_key_events();
[autoreleasePool drain];
autoreleasePool = [[NSAutoreleasePool alloc] init];
}
+void OS_OSX::process_key_events() {
+
+ Ref<InputEventKey> k;
+ for (int i = 0; i < key_event_pos; i++) {
+
+ KeyEvent &ke = key_event_buffer[i];
+
+ if ((i == 0 && ke.scancode == 0) || (i > 0 && key_event_buffer[i - 1].scancode == 0)) {
+ k.instance();
+
+ get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_scancode(0);
+ k->set_unicode(ke.unicode);
+
+ push_input(k);
+ }
+ if (ke.scancode != 0) {
+ k.instance();
+
+ get_key_modifier_state(ke.osx_state, k);
+ k->set_pressed(ke.pressed);
+ k->set_echo(ke.echo);
+ k->set_scancode(ke.scancode);
+
+ if (i + 1 < key_event_pos && key_event_buffer[i + 1].scancode == 0) {
+ k->set_unicode(key_event_buffer[i + 1].unicode);
+ }
+
+ push_input(k);
+ }
+ }
+
+ key_event_pos = 0;
+}
+
void OS_OSX::push_input(const Ref<InputEvent> &p_event) {
Ref<InputEvent> ev = p_event;
@@ -2184,6 +2289,7 @@ OS_OSX *OS_OSX::singleton = NULL;
OS_OSX::OS_OSX() {
+ key_event_pos = 0;
mouse_mode = OS::MOUSE_MODE_VISIBLE;
main_loop = NULL;
singleton = this;
@@ -2276,6 +2382,20 @@ OS_OSX::OS_OSX() {
Vector<Logger *> loggers;
loggers.push_back(memnew(OSXTerminalLogger));
_set_logger(memnew(CompositeLogger(loggers)));
+
+ //process application:openFile: event
+ while (true) {
+ NSEvent *event = [NSApp
+ nextEventMatchingMask:NSEventMaskAny
+ untilDate:[NSDate distantPast]
+ inMode:NSDefaultRunLoopMode
+ dequeue:YES];
+
+ if (event == nil)
+ break;
+
+ [NSApp sendEvent:event];
+ }
}
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
diff --git a/platform/server/detect.py b/platform/server/detect.py
index 72c9c770e3..bc615d3d04 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -67,9 +67,6 @@ def configure(env):
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
- if not env['builtin_openssl']:
- env.ParseConfig('pkg-config openssl --cflags --libs')
-
if not env['builtin_libwebp']:
env.ParseConfig('pkg-config libwebp --cflags --libs')
@@ -86,6 +83,16 @@ def configure(env):
if not env['builtin_libpng']:
env.ParseConfig('pkg-config libpng --cflags --libs')
+ if not env['builtin_bullet']:
+ # We need at least version 2.88
+ import subprocess
+ bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
+ if bullet_version < "2.88":
+ # Abort as system bullet was requested but too old
+ print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88"))
+ sys.exit(255)
+ env.ParseConfig('pkg-config bullet --cflags --libs')
+
if not env['builtin_enet']:
env.ParseConfig('pkg-config libenet --cflags --libs')
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 604896b0db..8965b80fb7 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -39,5 +39,5 @@ if env['vsproj']:
env.vs_srcs = env.vs_srcs + ["platform/windows/" + str(x)]
if not os.getenv("VCINSTALLDIR"):
- if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
+ if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
env.AddPostAction(prog, make_debug_mingw)
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index bd05d5605d..2b3743b066 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -69,6 +69,7 @@ def get_opts():
# Vista support dropped after EOL due to GH-10243
('target_win_version', 'Targeted Windows version, >= 0x0601 (Windows 7)', '0x0601'),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('separate_debug_symbols', 'Create a separate file with the debug symbols', False),
]
@@ -178,7 +179,7 @@ def configure(env):
if env["bits"] == "64":
env.Append(CCFLAGS=['/D_WIN64'])
- LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid']
+ LIBS = ['winmm', 'opengl32', 'dsound', 'kernel32', 'ole32', 'oleaut32', 'user32', 'gdi32', 'IPHLPAPI', 'Shlwapi', 'wsock32', 'Ws2_32', 'shell32', 'advapi32', 'dinput8', 'dxguid', 'Imm32']
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
env.Append(LIBPATH=[os.getenv("WindowsSdkDir") + "/Lib"])
@@ -280,7 +281,7 @@ def configure(env):
env.Append(CCFLAGS=['-DRTAUDIO_ENABLED'])
env.Append(CCFLAGS=['-DWASAPI_ENABLED'])
env.Append(CCFLAGS=['-DWINVER=%s' % env['target_win_version'], '-D_WIN32_WINNT=%s' % env['target_win_version']])
- env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser'])
+ env.Append(LIBS=['mingw32', 'opengl32', 'dsound', 'ole32', 'd3d9', 'winmm', 'gdi32', 'iphlpapi', 'shlwapi', 'wsock32', 'ws2_32', 'kernel32', 'oleaut32', 'dinput8', 'dxguid', 'ksuser', 'Imm32'])
env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 4f4b225b14..20129299a1 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -462,6 +462,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
case WM_MOUSEWHEEL:
case WM_MOUSEHWHEEL:
case WM_LBUTTONDBLCLK:
+ case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
/*case WM_XBUTTONDOWN:
case WM_XBUTTONUP: */ {
@@ -520,6 +521,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_button_index(2);
mb->set_doubleclick(true);
} break;
+ case WM_MBUTTONDBLCLK: {
+
+ mb->set_pressed(true);
+ mb->set_button_index(3);
+ mb->set_doubleclick(true);
+ } break;
case WM_MOUSEWHEEL: {
mb->set_pressed(true);
@@ -581,7 +588,7 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
mb->set_position(Vector2(old_x, old_y));
}
- if (uMsg != WM_MOUSEWHEEL) {
+ if (uMsg != WM_MOUSEWHEEL && uMsg != WM_MOUSEHWHEEL) {
if (mb->is_pressed()) {
if (++pressrc > 0)
@@ -1068,6 +1075,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
}
};
+ if (video_mode.always_on_top) {
+ SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+
#if defined(OPENGL_ENABLED)
gl_context = memnew(ContextGL_Win(hWnd, true));
gl_context->initialize();
@@ -1480,6 +1491,12 @@ Size2 OS_Windows::get_window_size() const {
GetClientRect(hWnd, &r);
return Vector2(r.right - r.left, r.bottom - r.top);
}
+Size2 OS_Windows::get_real_window_size() const {
+
+ RECT r;
+ GetWindowRect(hWnd, &r);
+ return Vector2(r.right - r.left, r.bottom - r.top);
+}
void OS_Windows::set_window_size(const Size2 p_size) {
video_mode.width = p_size.width;
@@ -1601,6 +1618,19 @@ bool OS_Windows::is_window_maximized() const {
return maximized;
}
+void OS_Windows::set_window_always_on_top(bool p_enabled) {
+ if (video_mode.always_on_top == p_enabled)
+ return;
+
+ video_mode.always_on_top = p_enabled;
+
+ _update_window_style();
+}
+
+bool OS_Windows::is_window_always_on_top() const {
+ return video_mode.always_on_top;
+}
+
void OS_Windows::set_borderless_window(bool p_borderless) {
if (video_mode.borderless_window == p_borderless)
return;
@@ -1625,6 +1655,8 @@ void OS_Windows::_update_window_style(bool repaint) {
}
}
+ SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
if (repaint) {
RECT rect;
GetWindowRect(hWnd, &rect);
@@ -1648,7 +1680,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
PRemoveDllDirectory remove_dll_directory = (PRemoveDllDirectory)GetProcAddress(GetModuleHandle("kernel32.dll"), "RemoveDllDirectory");
bool has_dll_directory_api = ((add_dll_directory != NULL) && (remove_dll_directory != NULL));
- DLL_DIRECTORY_COOKIE cookie;
+ DLL_DIRECTORY_COOKIE cookie = NULL;
if (p_also_set_library_path && has_dll_directory_api) {
cookie = add_dll_directory(path.get_base_dir().c_str());
@@ -1656,7 +1688,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
p_library_handle = (void *)LoadLibraryExW(path.c_str(), NULL, (p_also_set_library_path && has_dll_directory_api) ? LOAD_LIBRARY_SEARCH_DEFAULT_DIRS : 0);
- if (p_also_set_library_path && has_dll_directory_api) {
+ if (cookie) {
remove_dll_directory(cookie);
}
@@ -2204,6 +2236,36 @@ String OS_Windows::get_locale() const {
return "en";
}
+// We need this because GetSystemInfo() is unreliable on WOW64
+// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(v=vs.85).aspx
+// Taken from MSDN
+typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
+LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+BOOL is_wow64() {
+ BOOL wow64 = FALSE;
+
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
+
+ if (fnIsWow64Process) {
+ if (!fnIsWow64Process(GetCurrentProcess(), &wow64)) {
+ wow64 = FALSE;
+ }
+ }
+
+ return wow64;
+}
+
+int OS_Windows::get_processor_count() const {
+ SYSTEM_INFO sysinfo;
+ if (is_wow64())
+ GetNativeSystemInfo(&sysinfo);
+ else
+ GetSystemInfo(&sysinfo);
+
+ return sysinfo.dwNumberOfProcessors;
+}
+
OS::LatinKeyboardVariant OS_Windows::get_latin_keyboard_variant() const {
unsigned long azerty[] = {
@@ -2405,6 +2467,24 @@ String OS_Windows::get_user_data_dir() const {
return ProjectSettings::get_singleton()->get_resource_path();
}
+String OS_Windows::get_unique_id() const {
+
+ HW_PROFILE_INFO HwProfInfo;
+ ERR_FAIL_COND_V(!GetCurrentHwProfile(&HwProfInfo), "");
+ return String(HwProfInfo.szHwProfileGuid);
+}
+
+void OS_Windows::set_ime_position(const Point2 &p_pos) {
+
+ HIMC himc = ImmGetContext(hWnd);
+ COMPOSITIONFORM cps;
+ cps.dwStyle = CFS_FORCE_POSITION;
+ cps.ptCurrentPos.x = p_pos.x;
+ cps.ptCurrentPos.y = p_pos.y;
+ ImmSetCompositionWindow(himc, &cps);
+ ImmReleaseContext(hWnd, himc);
+}
+
bool OS_Windows::is_joy_known(int p_device) {
return input->is_joy_mapped(p_device);
}
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c24e35e929..4c4fbcf8f0 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -201,6 +201,7 @@ public:
virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
virtual Size2 get_window_size() const;
+ virtual Size2 get_real_window_size() const;
virtual void set_window_size(const Size2 p_size);
virtual void set_window_fullscreen(bool p_enabled);
virtual bool is_window_fullscreen() const;
@@ -210,6 +211,8 @@ public:
virtual bool is_window_minimized() const;
virtual void set_window_maximized(bool p_enabled);
virtual bool is_window_maximized() const;
+ virtual void set_window_always_on_top(bool p_enabled);
+ virtual bool is_window_always_on_top() const;
virtual void request_attention();
virtual void set_borderless_window(bool p_borderless);
@@ -253,6 +256,9 @@ public:
virtual String get_executable_path() const;
virtual String get_locale() const;
+
+ virtual int get_processor_count() const;
+
virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
virtual void enable_for_stealing_focus(ProcessID pid);
@@ -266,6 +272,10 @@ public:
virtual String get_system_dir(SystemDir p_dir) const;
virtual String get_user_data_dir() const;
+ virtual String get_unique_id() const;
+
+ virtual void set_ime_position(const Point2 &p_pos);
+
virtual void release_rendering_thread();
virtual void make_rendering_thread();
virtual void swap_buffers();
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index 38dd2ddd88..b18757337a 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -19,5 +19,5 @@ common_x11 = [
prog = env.add_program('#bin/godot', ['godot_x11.cpp'] + common_x11)
-if env["debug_symbols"] == "full" or env["debug_symbols"] == "yes":
+if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]:
env.AddPostAction(prog, make_debug)
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 478b42f9f7..c5ef82150b 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -55,6 +55,7 @@ def get_opts():
BoolVariable('pulseaudio', 'Detect & use pulseaudio', True),
BoolVariable('udev', 'Use udev for gamepad connection callbacks', False),
EnumVariable('debug_symbols', 'Add debug symbols to release version', 'yes', ('yes', 'no', 'full')),
+ BoolVariable('separate_debug_symbols', 'Create a separate file with the debug symbols', False),
BoolVariable('touch', 'Enable touch events', True),
]
@@ -64,7 +65,6 @@ def get_flags():
return [
('builtin_freetype', False),
('builtin_libpng', False),
- ('builtin_openssl', False),
('builtin_zlib', False),
]
@@ -152,8 +152,9 @@ def configure(env):
# FIXME: Check for existence of the libs before parsing their flags with pkg-config
- if not env['builtin_openssl']:
- env.ParseConfig('pkg-config openssl --cflags --libs')
+ if not env['builtin_mbedtls']:
+ # mbedTLS does not provide a pkgconfig config yet. See https://github.com/ARMmbed/mbedtls/issues/228
+ env.Append(LIBS=['mbedtls', 'mbedcrypto', 'mbedx509'])
if not env['builtin_libwebp']:
env.ParseConfig('pkg-config libwebp --cflags --libs')
@@ -172,6 +173,16 @@ def configure(env):
if not env['builtin_libpng']:
env.ParseConfig('pkg-config libpng --cflags --libs')
+ if not env['builtin_bullet']:
+ # We need at least version 2.88
+ import subprocess
+ bullet_version = subprocess.check_output(['pkg-config', 'bullet', '--modversion']).strip()
+ if bullet_version < "2.88":
+ # Abort as system bullet was requested but too old
+ print("Bullet: System version {0} does not match minimal requirements ({1}). Aborting.".format(bullet_version, "2.88"))
+ sys.exit(255)
+ env.ParseConfig('pkg-config bullet --cflags --libs')
+
if not env['builtin_enet']:
env.ParseConfig('pkg-config libenet --cflags --libs')
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index e4165e2fe3..2d8e32137f 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -217,7 +217,7 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
XIFreeDeviceInfo(info);
- if (!touch.devices.size()) {
+ if (is_stdout_verbose() && !touch.devices.size()) {
fprintf(stderr, "No touch devices found\n");
}
}
@@ -333,6 +333,11 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
XFree(xsh);
}
+ if (current_videomode.always_on_top) {
+ current_videomode.always_on_top = false;
+ set_window_always_on_top(true);
+ }
+
AudioDriverManager::initialize(p_audio_driver);
ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
@@ -549,6 +554,21 @@ void OS_X11::set_ime_position(const Point2 &p_pos) {
XFree(preedit_attr);
}
+String OS_X11::get_unique_id() const {
+
+ static String machine_id;
+ if (machine_id.empty()) {
+ if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) {
+ while (machine_id.empty() && !f->eof_reached()) {
+ machine_id = f->get_line().strip_edges();
+ }
+ f->close();
+ memdelete(f);
+ }
+ }
+ return machine_id;
+}
+
void OS_X11::finalize() {
if (main_loop)
@@ -710,9 +730,6 @@ void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) con
}
void OS_X11::set_wm_fullscreen(bool p_enabled) {
- if (current_videomode.fullscreen == p_enabled)
- return;
-
if (p_enabled && !is_window_resizable()) {
// Set the window as resizable to prevent window managers to ignore the fullscreen state flag.
XSizeHints *xsh;
@@ -773,6 +790,22 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
}
}
+void OS_X11::set_wm_above(bool p_enabled) {
+ Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
+ Atom wm_above = XInternAtom(x11_display, "_NET_WM_STATE_ABOVE", False);
+
+ XClientMessageEvent xev;
+ memset(&xev, 0, sizeof(xev));
+ xev.type = ClientMessage;
+ xev.window = x11_window;
+ xev.message_type = wm_state;
+ xev.format = 32;
+ xev.data.l[0] = p_enabled ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+ xev.data.l[1] = wm_above;
+ xev.data.l[3] = 1;
+ XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xev);
+}
+
int OS_X11::get_screen_count() const {
// Using Xinerama Extension
int event_base, error_base;
@@ -924,6 +957,26 @@ Size2 OS_X11::get_window_size() const {
return Size2i(current_videomode.width, current_videomode.height);
}
+Size2 OS_X11::get_real_window_size() const {
+ XWindowAttributes xwa;
+ XSync(x11_display, False);
+ XGetWindowAttributes(x11_display, x11_window, &xwa);
+ int w = xwa.width;
+ int h = xwa.height;
+ Atom prop = XInternAtom(x11_display, "_NET_FRAME_EXTENTS", True);
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = NULL;
+ if (XGetWindowProperty(x11_display, x11_window, prop, 0, 4, False, AnyPropertyType, &type, &format, &len, &remaining, &data) == Success) {
+ long *extents = (long *)data;
+ w += extents[0] + extents[1]; // left, right
+ h += extents[2] + extents[3]; // top, bottom
+ }
+ return Size2(w, h);
+}
+
void OS_X11::set_window_size(const Size2 p_size) {
// If window resizable is disabled we need to update the attributes first
if (is_window_resizable() == false) {
@@ -947,7 +1000,19 @@ void OS_X11::set_window_size(const Size2 p_size) {
}
void OS_X11::set_window_fullscreen(bool p_enabled) {
+ if (current_videomode.fullscreen == p_enabled)
+ return;
+
+ if (p_enabled && current_videomode.always_on_top) {
+ // Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
+ set_window_maximized(true);
+ }
set_wm_fullscreen(p_enabled);
+ if (!p_enabled && !current_videomode.always_on_top) {
+ // Restore
+ set_window_maximized(false);
+ }
+
current_videomode.fullscreen = p_enabled;
}
@@ -1154,6 +1219,27 @@ bool OS_X11::is_window_maximized() const {
return false;
}
+void OS_X11::set_window_always_on_top(bool p_enabled) {
+ if (is_window_always_on_top() == p_enabled)
+ return;
+
+ if (p_enabled && current_videomode.fullscreen) {
+ // Fullscreen + Always-on-top requires a maximized window on some window managers (Metacity)
+ set_window_maximized(true);
+ }
+ set_wm_above(p_enabled);
+ if (!p_enabled && !current_videomode.fullscreen) {
+ // Restore
+ set_window_maximized(false);
+ }
+
+ current_videomode.always_on_top = p_enabled;
+}
+
+bool OS_X11::is_window_always_on_top() const {
+ return current_videomode.always_on_top;
+}
+
void OS_X11::set_borderless_window(bool p_borderless) {
if (current_videomode.borderless_window == p_borderless)
@@ -1862,8 +1948,12 @@ void OS_X11::process_xevents() {
e = event;
req = &(e.xselectionrequest);
- if (req->target == XA_STRING || req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- req->target == XInternAtom(x11_display, "UTF8_STRING", 0)) {
+ if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+ req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ req->target == XInternAtom(x11_display, "TEXT", 0) ||
+ req->target == XA_STRING ||
+ req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ req->target == XInternAtom(x11_display, "text/plain", 0)) {
CharString clip = OS::get_clipboard().utf8();
XChangeProperty(x11_display,
req->requestor,
@@ -1876,26 +1966,40 @@ void OS_X11::process_xevents() {
respond.xselection.property = req->property;
} else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) {
- Atom data[2];
- data[0] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[1] = XA_STRING;
- XChangeProperty(x11_display, req->requestor, req->property, req->target,
- 8, PropModeReplace, (unsigned char *)&data,
- sizeof(data));
+ Atom data[7];
+ data[0] = XInternAtom(x11_display, "TARGETS", 0);
+ data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+ data[3] = XInternAtom(x11_display, "TEXT", 0);
+ data[4] = XA_STRING;
+ data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+ data[6] = XInternAtom(x11_display, "text/plain", 0);
+
+ XChangeProperty(x11_display,
+ req->requestor,
+ req->property,
+ XA_ATOM,
+ 32,
+ PropModeReplace,
+ (unsigned char *)&data,
+ sizeof(data) / sizeof(data[0]));
respond.xselection.property = req->property;
} else {
- printf("No String %x\n",
- (int)req->target);
+ char *targetname = XGetAtomName(x11_display, req->target);
+ printf("No Target '%s'\n", targetname);
+ if (targetname)
+ XFree(targetname);
respond.xselection.property = None;
}
+
respond.xselection.type = SelectionNotify;
respond.xselection.display = req->display;
respond.xselection.requestor = req->requestor;
respond.xselection.selection = req->selection;
respond.xselection.target = req->target;
respond.xselection.time = req->time;
- XSendEvent(x11_display, req->requestor, 0, 0, &respond);
+ XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond);
XFlush(x11_display);
} break;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index f7bc0b73e0..494845bc56 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -178,6 +178,7 @@ class OS_X11 : public OS_Unix {
bool maximized;
//void set_wm_border(bool p_enabled);
void set_wm_fullscreen(bool p_enabled);
+ void set_wm_above(bool p_enabled);
typedef xrr_monitor_info *(*xrr_get_monitors_t)(Display *dpy, Window window, Bool get_active, int *nmonitors);
typedef void (*xrr_free_monitors_t)(xrr_monitor_info *monitors);
@@ -199,7 +200,7 @@ protected:
virtual void set_main_loop(MainLoop *p_main_loop);
- void _window_changed(XEvent *xevent);
+ void _window_changed(XEvent *event);
bool is_window_maximize_allowed();
@@ -251,6 +252,7 @@ public:
virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2 &p_position);
virtual Size2 get_window_size() const;
+ virtual Size2 get_real_window_size() const;
virtual void set_window_size(const Size2 p_size);
virtual void set_window_fullscreen(bool p_enabled);
virtual bool is_window_fullscreen() const;
@@ -260,12 +262,16 @@ public:
virtual bool is_window_minimized() const;
virtual void set_window_maximized(bool p_enabled);
virtual bool is_window_maximized() const;
+ virtual void set_window_always_on_top(bool p_enabled);
+ virtual bool is_window_always_on_top() const;
virtual void request_attention();
virtual void set_borderless_window(bool p_borderless);
virtual bool get_borderless_window();
virtual void set_ime_position(const Point2 &p_pos);
+ virtual String get_unique_id() const;
+
virtual void move_window_to_foreground();
virtual void alert(const String &p_alert, const String &p_title = "ALERT!");