summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/AndroidManifest.xml.template10
-rw-r--r--platform/android/SCsub8
-rw-r--r--platform/android/export/export.cpp57
-rw-r--r--platform/android/file_access_android.cpp2
-rw-r--r--platform/android/file_access_android.h2
-rw-r--r--platform/android/file_access_jandroid.cpp2
-rw-r--r--platform/android/file_access_jandroid.h2
-rw-r--r--platform/android/os_android.cpp7
-rw-r--r--platform/android/power_android.cpp16
-rw-r--r--platform/android/power_android.h6
-rw-r--r--platform/haiku/haiku_direct_window.cpp8
-rw-r--r--platform/haiku/os_haiku.cpp6
-rw-r--r--platform/haiku/os_haiku.h2
-rw-r--r--platform/haiku/power_haiku.cpp6
-rw-r--r--platform/haiku/power_haiku.h6
-rw-r--r--platform/iphone/game_center.mm1
-rw-r--r--platform/iphone/power_iphone.cpp8
-rw-r--r--platform/iphone/power_iphone.h6
-rw-r--r--platform/javascript/SCsub33
-rw-r--r--platform/javascript/detect.py2
-rw-r--r--platform/javascript/engine.js366
-rw-r--r--platform/javascript/export/export.cpp30
-rw-r--r--platform/javascript/godot_shell.html347
-rw-r--r--platform/javascript/os_javascript.cpp24
-rw-r--r--platform/javascript/os_javascript.h2
-rw-r--r--platform/javascript/power_javascript.cpp6
-rw-r--r--platform/javascript/power_javascript.h6
-rw-r--r--platform/javascript/pre_asmjs.js3
-rw-r--r--platform/javascript/pre_wasm.js3
-rw-r--r--platform/osx/SCsub7
-rw-r--r--platform/osx/audio_driver_osx.cpp11
-rw-r--r--platform/osx/crash_handler_osx.h47
-rw-r--r--platform/osx/crash_handler_osx.mm179
-rw-r--r--platform/osx/dir_access_osx.h3
-rw-r--r--platform/osx/dir_access_osx.mm18
-rw-r--r--platform/osx/export/export.cpp15
-rw-r--r--platform/osx/godot_main_osx.mm8
-rw-r--r--platform/osx/os_osx.h11
-rw-r--r--platform/osx/os_osx.mm32
-rw-r--r--platform/osx/power_osx.cpp16
-rw-r--r--platform/osx/power_osx.h6
-rw-r--r--platform/server/os_server.cpp10
-rw-r--r--platform/server/os_server.h4
-rw-r--r--platform/uwp/export/export.cpp8
-rw-r--r--platform/uwp/os_uwp.cpp9
-rw-r--r--platform/uwp/os_uwp.h2
-rw-r--r--platform/uwp/power_uwp.cpp6
-rw-r--r--platform/uwp/power_uwp.h6
-rw-r--r--platform/windows/SCsub3
-rw-r--r--platform/windows/context_gl_win.cpp16
-rw-r--r--platform/windows/crash_handler_win.cpp211
-rw-r--r--platform/windows/crash_handler_win.h56
-rw-r--r--platform/windows/detect.py11
-rw-r--r--platform/windows/godot_win.cpp20
-rw-r--r--platform/windows/joypad.cpp4
-rw-r--r--platform/windows/os_windows.cpp52
-rw-r--r--platform/windows/os_windows.h10
-rw-r--r--platform/windows/power_windows.cpp18
-rw-r--r--platform/windows/power_windows.h6
-rw-r--r--platform/x11/SCsub13
-rw-r--r--platform/x11/crash_handler_x11.cpp136
-rw-r--r--platform/x11/crash_handler_x11.h47
-rw-r--r--platform/x11/detect.py1
-rw-r--r--platform/x11/export/export.cpp1
-rw-r--r--platform/x11/joypad_linux.cpp1
-rw-r--r--platform/x11/os_x11.cpp63
-rw-r--r--platform/x11/os_x11.h18
-rw-r--r--platform/x11/power_x11.cpp42
-rw-r--r--platform/x11/power_x11.h6
69 files changed, 1425 insertions, 685 deletions
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template
index be5afb406a..9d8eb951c4 100644
--- a/platform/android/AndroidManifest.xml.template
+++ b/platform/android/AndroidManifest.xml.template
@@ -17,7 +17,7 @@
android:launchMode="singleTask"
android:screenOrientation="landscape"
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize">
-
+
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -26,7 +26,7 @@
<service android:name="org.godotengine.godot.GodotDownloaderService" />
-
+
$$ADD_APPLICATION_CHUNKS$$
@@ -200,6 +200,6 @@ $$ADD_PERMISSION_CHUNKS$$
<uses-permission android:name="godot.custom.18"/>
<uses-permission android:name="godot.custom.19"/>
-<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="23"/>
-
-</manifest>
+<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="23"/>
+
+</manifest>
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 87e7ee4747..e9a370869f 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -73,7 +73,7 @@ for x in env.android_gradle_plugins:
gradle_classpath = ""
for x in env.android_gradle_classpath:
gradle_classpath += "\t\tclasspath \"" + x + "\"\n"
-
+
gradle_res_dirs_text = ""
for x in env.android_res_dirs:
@@ -93,13 +93,13 @@ gradle_asset_dirs_text = ""
gradle_default_config_text = ""
-minSdk = 14
+minSdk = 18
targetSdk = 23
for x in env.android_default_config:
- if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk:
+ if x.startswith("minSdkVersion") and int(x.split(" ")[-1]) < minSdk:
x = "minSdkVersion " + str(minSdk)
- if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk:
+ if x.startswith("targetSdkVersion") and int(x.split(" ")[-1]) > targetSdk:
x = "targetSdkVersion " + str(targetSdk)
gradle_default_config_text += x + "\n\t\t"
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index d691bd7629..e3615e2298 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -520,25 +520,21 @@ class EditorExportAndroid : public EditorExportPlatform {
void _fix_manifest(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_manifest, bool p_give_internet) {
- const int CHUNK_AXML_FILE = 0x00080003;
- const int CHUNK_RESOURCEIDS = 0x00080180;
+ // Leaving the unused types commented because looking these constants up
+ // again later would be annoying
+ // const int CHUNK_AXML_FILE = 0x00080003;
+ // const int CHUNK_RESOURCEIDS = 0x00080180;
const int CHUNK_STRINGS = 0x001C0001;
- const int CHUNK_XML_END_NAMESPACE = 0x00100101;
- const int CHUNK_XML_END_TAG = 0x00100103;
- const int CHUNK_XML_START_NAMESPACE = 0x00100100;
+ // const int CHUNK_XML_END_NAMESPACE = 0x00100101;
+ // const int CHUNK_XML_END_TAG = 0x00100103;
+ // const int CHUNK_XML_START_NAMESPACE = 0x00100100;
const int CHUNK_XML_START_TAG = 0x00100102;
- const int CHUNK_XML_TEXT = 0x00100104;
+ // const int CHUNK_XML_TEXT = 0x00100104;
const int UTF8_FLAG = 0x00000100;
Vector<String> string_table;
- uint32_t ofs = 0;
-
- uint32_t header = decode_uint32(&p_manifest[ofs]);
- uint32_t filesize = decode_uint32(&p_manifest[ofs + 4]);
- ofs += 8;
-
- //print_line("FILESIZE: "+itos(filesize)+" ACTUAL: "+itos(p_manifest.size()));
+ uint32_t ofs = 8;
uint32_t string_count = 0;
uint32_t styles_count = 0;
@@ -646,24 +642,16 @@ class EditorExportAndroid : public EditorExportPlatform {
case CHUNK_XML_START_TAG: {
int iofs = ofs + 8;
- uint32_t line = decode_uint32(&p_manifest[iofs]);
- uint32_t nspace = decode_uint32(&p_manifest[iofs + 8]);
uint32_t name = decode_uint32(&p_manifest[iofs + 12]);
- uint32_t check = decode_uint32(&p_manifest[iofs + 16]);
String tname = string_table[name];
-
- //printf("NSPACE: %i\n",nspace);
- //printf("NAME: %i (%s)\n",name,tname.utf8().get_data());
- //printf("CHECK: %x\n",check);
uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]);
iofs += 28;
- //printf("ATTRCOUNT: %x\n",attrcount);
+
for (uint32_t i = 0; i < attrcount; i++) {
uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]);
uint32_t attr_name = decode_uint32(&p_manifest[iofs + 4]);
uint32_t attr_value = decode_uint32(&p_manifest[iofs + 8]);
- uint32_t attr_flags = decode_uint32(&p_manifest[iofs + 12]);
uint32_t attr_resid = decode_uint32(&p_manifest[iofs + 16]);
String value;
@@ -678,12 +666,6 @@ class EditorExportAndroid : public EditorExportPlatform {
else
nspace = "";
- //printf("ATTR %i NSPACE: %i\n",i,attr_nspace);
- //printf("ATTR %i NAME: %i (%s)\n",i,attr_name,attrname.utf8().get_data());
- //printf("ATTR %i VALUE: %i (%s)\n",i,attr_value,value.utf8().get_data());
- //printf("ATTR %i FLAGS: %x\n",i,attr_flags);
- //printf("ATTR %i RESID: %x\n",i,attr_resid);
-
//replace project information
if (tname == "manifest" && attrname == "package") {
@@ -691,9 +673,6 @@ class EditorExportAndroid : public EditorExportPlatform {
string_table[attr_value] = get_package_name(package_name);
}
- //print_line("tname: "+tname);
- //print_line("nspace: "+nspace);
- //print_line("attrname: "+attrname);
if (tname == "manifest" && /*nspace=="android" &&*/ attrname == "versionCode") {
print_line("FOUND versionCode");
@@ -712,13 +691,6 @@ class EditorExportAndroid : public EditorExportPlatform {
if (tname == "activity" && /*nspace=="android" &&*/ attrname == "screenOrientation") {
encode_uint32(orientation == 0 ? 0 : 1, &p_manifest[iofs + 16]);
- /*
- print_line("FOUND screen orientation");
- if (attr_value==0xFFFFFFFF) {
- WARN_PRINT("Version name in a resource, should be plaintext")
- } else {
- string_table[attr_value]=(orientation==0?"landscape":"portrait");
- }*/
}
if (tname == "uses-feature" && /*nspace=="android" &&*/ attrname == "glEsVersion") {
@@ -771,13 +743,10 @@ class EditorExportAndroid : public EditorExportPlatform {
} break;
}
- //printf("chunk %x: size: %d\n",chunk,size);
ofs += size;
}
- //printf("end\n");
-
//create new andriodmanifest binary
Vector<uint8_t> ret;
@@ -876,8 +845,6 @@ class EditorExportAndroid : public EditorExportPlatform {
const int UTF8_FLAG = 0x00000100;
print_line("*******************GORRRGLE***********************");
- uint32_t header = decode_uint32(&p_manifest[0]);
- uint32_t filesize = decode_uint32(&p_manifest[4]);
uint32_t string_block_len = decode_uint32(&p_manifest[16]);
uint32_t string_count = decode_uint32(&p_manifest[20]);
uint32_t string_flags = decode_uint32(&p_manifest[28]);
@@ -887,10 +854,6 @@ class EditorExportAndroid : public EditorExportPlatform {
String package_name = p_preset->get("package/name");
- //printf("stirng block len: %i\n",string_block_len);
- //printf("stirng count: %i\n",string_count);
- //printf("flags: %x\n",string_flags);
-
for (uint32_t i = 0; i < string_count; i++) {
uint32_t offset = decode_uint32(&p_manifest[string_table_begins + i * 4]);
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index f207b81b4b..c7b0d9afcd 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -95,7 +95,7 @@ void FileAccessAndroid::seek_end(int64_t p_position) {
pos = len + p_position;
}
-size_t FileAccessAndroid::get_pos() const {
+size_t FileAccessAndroid::get_position() const {
return pos;
}
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index c2ce2b0bfe..beccf494dd 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -53,7 +53,7 @@ public:
virtual void seek(size_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_position() const; ///< get position in the file
virtual size_t get_len() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
index ad855c790d..fe934c89fb 100644
--- a/platform/android/file_access_jandroid.cpp
+++ b/platform/android/file_access_jandroid.cpp
@@ -106,7 +106,7 @@ void FileAccessJAndroid::seek_end(int64_t p_position) {
seek(get_len());
}
-size_t FileAccessJAndroid::get_pos() const {
+size_t FileAccessJAndroid::get_position() const {
JNIEnv *env = ThreadAndroid::get_env();
ERR_FAIL_COND_V(!is_open(), 0);
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
index 8060312182..75a6a21335 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/file_access_jandroid.h
@@ -57,7 +57,7 @@ public:
virtual void seek(size_t p_position); ///< seek to a given position
virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file
- virtual size_t get_pos() const; ///< get position in the file
+ virtual size_t get_position() const; ///< get position in the file
virtual size_t get_len() const; ///< get size of the file
virtual bool eof_reached() const; ///< reading passed EOF
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 1de2608b9e..dbea2d7531 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -137,12 +137,7 @@ void OS_Android::initialize(const VideoMode &p_desired, int p_video_driver, int
visual_server->init();
// visual_server->cursor_set_visible(false, 0);
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
physics_server = memnew(PhysicsServerSW);
physics_server->init();
diff --git a/platform/android/power_android.cpp b/platform/android/power_android.cpp
index 98d4d810b9..48c9377a5a 100644
--- a/platform/android/power_android.cpp
+++ b/platform/android/power_android.cpp
@@ -198,19 +198,19 @@ bool power_android::GetPowerInfo_Android() {
if (Android_JNI_GetPowerInfo(&plugged, &charged, &battery, &this->nsecs_left, &this->percent_left) != -1) {
if (plugged) {
if (charged) {
- this->power_state = POWERSTATE_CHARGED;
+ this->power_state = OS::POWERSTATE_CHARGED;
} else if (battery) {
- this->power_state = POWERSTATE_CHARGING;
+ this->power_state = OS::POWERSTATE_CHARGING;
} else {
- this->power_state = POWERSTATE_NO_BATTERY;
+ this->power_state = OS::POWERSTATE_NO_BATTERY;
this->nsecs_left = -1;
this->percent_left = -1;
}
} else {
- this->power_state = POWERSTATE_ON_BATTERY;
+ this->power_state = OS::POWERSTATE_ON_BATTERY;
}
} else {
- this->power_state = POWERSTATE_UNKNOWN;
+ this->power_state = OS::POWERSTATE_UNKNOWN;
this->nsecs_left = -1;
this->percent_left = -1;
}
@@ -218,12 +218,12 @@ bool power_android::GetPowerInfo_Android() {
return true;
}
-PowerState power_android::get_power_state() {
+OS::PowerState power_android::get_power_state() {
if (GetPowerInfo_Android()) {
return power_state;
} else {
WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN");
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -246,7 +246,7 @@ int power_android::get_power_percent_left() {
}
power_android::power_android()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
power_android::~power_android() {
diff --git a/platform/android/power_android.h b/platform/android/power_android.h
index fc618c660d..4c7af1c771 100644
--- a/platform/android/power_android.h
+++ b/platform/android/power_android.h
@@ -31,7 +31,7 @@
#ifndef PLATFORM_ANDROID_POWER_ANDROID_H_
#define PLATFORM_ANDROID_POWER_ANDROID_H_
-#include "os/power.h"
+#include "os/os.h"
#include <android/native_window_jni.h>
class power_android {
@@ -57,7 +57,7 @@ private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool GetPowerInfo_Android();
bool UpdatePowerInfo();
@@ -71,7 +71,7 @@ public:
static struct LocalReferenceHolder LocalReferenceHolder_Setup(const char *func);
static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder);
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp
index 572df493ff..24a8a4b17b 100644
--- a/platform/haiku/haiku_direct_window.cpp
+++ b/platform/haiku/haiku_direct_window.cpp
@@ -157,8 +157,8 @@ void HaikuDirectWindow::HandleMouseButton(BMessage *message) {
mouse_event.mouse_button.mod = GetKeyModifierState(modifiers);
mouse_event->get_button_mask() = GetMouseButtonState(buttons);
- mouse_event->get_pos().x = where.x;
- mouse_event->get_pos().y = where.y;
+ mouse_event->get_position().x = where.x;
+ mouse_event->get_position().y = where.y;
mouse_event.mouse_button.global_x = where.x;
mouse_event.mouse_button.global_y = where.y;
@@ -242,8 +242,8 @@ void HaikuDirectWindow::HandleMouseWheelChanged(BMessage *message) {
mouse_event->get_button_index() = wheel_delta_y < 0 ? 4 : 5;
mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state);
mouse_event->get_button_mask() = last_button_mask;
- mouse_event->get_pos().x = last_mouse_position.x;
- mouse_event->get_pos().y = last_mouse_position.y;
+ mouse_event->get_position().x = last_mouse_position.x;
+ mouse_event->get_position().y = last_mouse_position.y;
mouse_event.mouse_button.global_x = last_mouse_position.x;
mouse_event.mouse_button.global_y = last_mouse_position.y;
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
index de2f79a0ac..9f2f88bb4e 100644
--- a/platform/haiku/os_haiku.cpp
+++ b/platform/haiku/os_haiku.cpp
@@ -137,11 +137,7 @@ void OS_Haiku::initialize(const VideoMode &p_desired, int p_video_driver, int p_
//physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
physics_2d_server->init();
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
power_manager = memnew(PowerHaiku);
}
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
index cb68f9303f..d2fafb9129 100644
--- a/platform/haiku/os_haiku.h
+++ b/platform/haiku/os_haiku.h
@@ -117,7 +117,7 @@ public:
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
virtual String get_executable_path() const;
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
diff --git a/platform/haiku/power_haiku.cpp b/platform/haiku/power_haiku.cpp
index 449b43a621..8718b317a3 100644
--- a/platform/haiku/power_haiku.cpp
+++ b/platform/haiku/power_haiku.cpp
@@ -37,12 +37,12 @@ bool PowerHaiku::UpdatePowerInfo() {
return false;
}
-PowerState PowerHaiku::get_power_state() {
+OS::PowerState PowerHaiku::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN");
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -65,7 +65,7 @@ int PowerX11::get_power_percent_left() {
}
PowerHaiku::PowerHaiku()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerHaiku::~PowerHaiku() {
diff --git a/platform/haiku/power_haiku.h b/platform/haiku/power_haiku.h
index 12513bdaef..59a93cd976 100644
--- a/platform/haiku/power_haiku.h
+++ b/platform/haiku/power_haiku.h
@@ -31,11 +31,13 @@
#ifndef PLATFORM_HAIKU_POWER_HAIKU_H_
#define PLATFORM_HAIKU_POWER_HAIKU_H_
+#include <os/os.h>
+
class PowerHaiku {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool UpdatePowerInfo();
@@ -43,7 +45,7 @@ public:
PowerHaiku();
virtual ~PowerHaiku();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
index c05bdea005..821ef2a3ab 100644
--- a/platform/iphone/game_center.mm
+++ b/platform/iphone/game_center.mm
@@ -89,6 +89,7 @@ Error GameCenter::connect() {
ret["type"] = "authentication";
if (player.isAuthenticated) {
ret["result"] = "ok";
+ ret["player_id"] = player.playerID;
GameCenter::get_singleton()->connected = true;
} else {
ret["result"] = "error";
diff --git a/platform/iphone/power_iphone.cpp b/platform/iphone/power_iphone.cpp
index 2811e62108..055d31ef0a 100644
--- a/platform/iphone/power_iphone.cpp
+++ b/platform/iphone/power_iphone.cpp
@@ -30,15 +30,15 @@
#include "power_iphone.h"
-bool PowerState::UpdatePowerInfo() {
+bool OS::PowerState::UpdatePowerInfo() {
return false;
}
-PowerState PowerIphone::get_power_state() {
+OS::PowerState PowerIphone::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -59,7 +59,7 @@ int PowerIphone::get_power_percent_left() {
}
PowerIphone::PowerIphone()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
// TODO Auto-generated constructor stub
}
diff --git a/platform/iphone/power_iphone.h b/platform/iphone/power_iphone.h
index b4fb8d62dc..6270a8069c 100644
--- a/platform/iphone/power_iphone.h
+++ b/platform/iphone/power_iphone.h
@@ -31,11 +31,13 @@
#ifndef PLATFORM_IPHONE_POWER_IPHONE_H_
#define PLATFORM_IPHONE_POWER_IPHONE_H_
+#include <os/os.h>
+
class PowerIphone {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool UpdatePowerInfo();
@@ -43,7 +45,7 @@ public:
PowerIphone();
virtual ~PowerIphone();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index b804863ee1..e282041745 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -20,33 +20,32 @@ for x in javascript_files:
javascript_objects.append(env_javascript.Object(x))
env.Append(LINKFLAGS=["-s", "EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync','_send_notification']\""])
-env.Append(LINKFLAGS=["--shell-file", '"platform/javascript/godot_shell.html"'])
# output file name without file extension
basename = "godot" + env["PROGSUFFIX"]
target_dir = env.Dir("#bin")
-js_file = target_dir.File(basename + ".js")
-implicit_targets = [js_file]
zip_dir = target_dir.Dir('.javascript_zip')
-zip_files = env.InstallAs([zip_dir.File("godot.js"), zip_dir.File("godotfs.js")], [js_file, "#misc/dist/html_fs/godotfs.js"])
+zip_files = env.InstallAs(zip_dir.File('godot.html'), '#misc/dist/html/default.html')
+implicit_targets = []
if env['wasm'] == 'yes':
- wasm_file = target_dir.File(basename+'.wasm')
- implicit_targets.append(wasm_file)
- zip_files.append(InstallAs(zip_dir.File('godot.wasm'), wasm_file))
+ wasm = target_dir.File(basename + '.wasm')
+ implicit_targets.append(wasm)
+ zip_files.append(InstallAs(zip_dir.File('godot.wasm'), wasm))
+ prejs = env.File('pre_wasm.js')
else:
- asmjs_files = [target_dir.File(basename+'.asm.js'), target_dir.File(basename+'.html.mem')]
- zip_files.append(InstallAs([zip_dir.File('godot.asm.js'), zip_dir.File('godot.mem')], asmjs_files))
+ asmjs_files = [target_dir.File(basename + '.asm.js'), target_dir.File(basename + '.js.mem')]
implicit_targets.extend(asmjs_files)
+ zip_files.append(InstallAs([zip_dir.File('godot.asm.js'), zip_dir.File('godot.mem')], asmjs_files))
+ prejs = env.File('pre_asmjs.js')
-# HTML file must be the first target in the list
-html_file = env.Program(["#bin/godot"] + implicit_targets, javascript_objects, PROGSUFFIX=env["PROGSUFFIX"]+".html")[0]
-Depends(html_file, "godot_shell.html")
+js = env.Program(['#bin/godot'] + implicit_targets, javascript_objects, PROGSUFFIX=env['PROGSUFFIX'] + '.js')[0];
+zip_files.append(InstallAs(zip_dir.File('godot.js'), js))
-# Emscripten hardcodes file names, so replace common base name with
-# placeholder while leaving extension; also change `.html.mem` to just `.mem`
-fixup_html = env.Substfile(html_file, SUBST_DICT=[(basename, '$$GODOT_BASE'), ('.html.mem', '.mem')], SUBSTFILESUFFIX='.fixup.html')
+postjs = env.File('engine.js')
+env.Depends(js, [prejs, postjs])
+env.Append(LINKFLAGS=['--pre-js', prejs.path])
+env.Append(LINKFLAGS=['--post-js', postjs.path])
-zip_files.append(InstallAs(zip_dir.File('godot.html'), fixup_html))
-Zip('#bin/godot', zip_files, ZIPSUFFIX=env['PROGSUFFIX']+env['ZIPSUFFIX'], ZIPROOT=zip_dir, ZIPCOMSTR="Archving $SOURCES as $TARGET")
+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 5f066f1b15..bea8f156af 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -100,6 +100,7 @@ def configure(env):
## Link flags
+ env.Append(LINKFLAGS=['-s', 'EXTRA_EXPORTED_RUNTIME_METHODS="[\'FS\']"'])
env.Append(LINKFLAGS=['-s', 'USE_WEBGL2=1'])
if (env['wasm'] == 'yes'):
@@ -112,6 +113,7 @@ def configure(env):
else:
env.Append(LINKFLAGS=['-s', 'ASM_JS=1'])
env.Append(LINKFLAGS=['--separate-asm'])
+ env.Append(LINKFLAGS=['--memory-init-file', '1'])
# TODO: Move that to opus module's config
if("module_opus_enabled" in env and env["module_opus_enabled"] != "no"):
diff --git a/platform/javascript/engine.js b/platform/javascript/engine.js
new file mode 100644
index 0000000000..552f5a7e02
--- /dev/null
+++ b/platform/javascript/engine.js
@@ -0,0 +1,366 @@
+ return Module;
+ },
+};
+
+(function() {
+ var engine = Engine;
+
+ var USING_WASM = engine.USING_WASM;
+ var DOWNLOAD_ATTEMPTS_MAX = 4;
+
+ var basePath = null;
+ var engineLoadPromise = null;
+
+ var loadingFiles = {};
+
+ function getBasePath(path) {
+
+ if (path.endsWith('/'))
+ path = path.slice(0, -1);
+ if (path.lastIndexOf('.') > path.lastIndexOf('/'))
+ path = path.slice(0, path.lastIndexOf('.'));
+ return path;
+ }
+
+ function getBaseName(path) {
+
+ path = getBasePath(path);
+ return path.slice(path.lastIndexOf('/') + 1);
+ }
+
+ Engine = function Engine() {
+
+ this.rtenv = null;
+
+ var gameInitPromise = null;
+ var unloadAfterInit = true;
+ var memorySize = 268435456;
+
+ var progressFunc = null;
+ var pckProgressTracker = {};
+ var lastProgress = { loaded: 0, total: 0 };
+
+ var canvas = null;
+ var stdout = null;
+ var stderr = null;
+
+ this.initGame = function(mainPack) {
+
+ if (!gameInitPromise) {
+
+ if (mainPack === undefined) {
+ if (basePath !== null) {
+ mainPack = basePath + '.pck';
+ } else {
+ return Promise.reject(new Error("No main pack to load specified"));
+ }
+ }
+ if (basePath === null)
+ basePath = getBasePath(mainPack);
+
+ gameInitPromise = Engine.initEngine().then(
+ instantiate.bind(this)
+ );
+ var gameLoadPromise = loadPromise(mainPack, pckProgressTracker).then(function(xhr) { return xhr.response; });
+ gameInitPromise = Promise.all([gameLoadPromise, gameInitPromise]).then(function(values) {
+ // resolve with pck
+ return new Uint8Array(values[0]);
+ });
+ if (unloadAfterInit)
+ gameInitPromise.then(Engine.unloadEngine);
+ requestAnimationFrame(animateProgress);
+ }
+ return gameInitPromise;
+ };
+
+ function instantiate(initializer) {
+
+ var rtenvOpts = {
+ noInitialRun: true,
+ thisProgram: getBaseName(basePath),
+ engine: this,
+ };
+ if (typeof stdout === 'function')
+ rtenvOpts.print = stdout;
+ if (typeof stderr === 'function')
+ rtenvOpts.printErr = stderr;
+ if (typeof WebAssembly === 'object' && initializer instanceof WebAssembly.Module) {
+ rtenvOpts.instantiateWasm = function(imports, onSuccess) {
+ WebAssembly.instantiate(initializer, imports).then(function(result) {
+ onSuccess(result);
+ });
+ return {};
+ };
+ } else if (initializer.asm && initializer.mem) {
+ rtenvOpts.asm = initializer.asm;
+ rtenvOpts.memoryInitializerRequest = initializer.mem;
+ rtenvOpts.TOTAL_MEMORY = memorySize;
+ } else {
+ throw new Error("Invalid initializer");
+ }
+
+ return new Promise(function(resolve, reject) {
+ rtenvOpts.onRuntimeInitialized = resolve;
+ rtenvOpts.onAbort = reject;
+ rtenvOpts.engine.rtenv = Engine.RuntimeEnvironment(rtenvOpts);
+ });
+ }
+
+ this.start = function(mainPack) {
+
+ return this.initGame(mainPack).then(synchronousStart.bind(this));
+ };
+
+ function synchronousStart(pckView) {
+ // TODO don't expect canvas when runninng as cli tool
+ if (canvas instanceof HTMLCanvasElement) {
+ this.rtenv.canvas = canvas;
+ } else {
+ var firstCanvas = document.getElementsByTagName('canvas')[0];
+ if (firstCanvas instanceof HTMLCanvasElement) {
+ this.rtenv.canvas = firstCanvas;
+ } else {
+ throw new Error("No canvas found");
+ }
+ }
+
+ var actualCanvas = this.rtenv.canvas;
+ var context = false;
+ try {
+ context = actualCanvas.getContext('webgl2') || actualCanvas.getContext('experimental-webgl2');
+ } catch (e) {}
+ if (!context) {
+ throw new Error("WebGL 2 not available");
+ }
+
+ // canvas can grab focus on click
+ if (actualCanvas.tabIndex < 0) {
+ actualCanvas.tabIndex = 0;
+ }
+ // necessary to calculate cursor coordinates correctly
+ actualCanvas.style.padding = 0;
+ actualCanvas.style.borderWidth = 0;
+ actualCanvas.style.borderStyle = 'none';
+ // until context restoration is implemented
+ actualCanvas.addEventListener('webglcontextlost', function(ev) {
+ alert("WebGL context lost, please reload the page");
+ ev.preventDefault();
+ }, false);
+
+ this.rtenv.FS.createDataFile('/', this.rtenv.thisProgram + '.pck', pckView, true, true, true);
+ gameInitPromise = null;
+ this.rtenv.callMain();
+ }
+
+ this.setProgressFunc = function(func) {
+ progressFunc = func;
+ };
+
+ function animateProgress() {
+
+ var loaded = 0;
+ var total = 0;
+ var totalIsValid = true;
+ var progressIsFinal = true;
+
+ [loadingFiles, pckProgressTracker].forEach(function(tracker) {
+ Object.keys(tracker).forEach(function(file) {
+ if (!tracker[file].final)
+ progressIsFinal = false;
+ if (!totalIsValid || tracker[file].total === 0) {
+ totalIsValid = false;
+ total = 0;
+ } else {
+ total += tracker[file].total;
+ }
+ loaded += tracker[file].loaded;
+ });
+ });
+ if (loaded !== lastProgress.loaded || total !== lastProgress.total) {
+ lastProgress.loaded = loaded;
+ lastProgress.total = total;
+ if (typeof progressFunc === 'function')
+ progressFunc(loaded, total);
+ }
+ if (!progressIsFinal)
+ requestAnimationFrame(animateProgress);
+ }
+
+ this.setCanvas = function(elem) {
+ canvas = elem;
+ };
+
+ this.setAsmjsMemorySize = function(size) {
+ memorySize = size;
+ };
+
+ this.setUnloadAfterInit = function(enabled) {
+
+ if (enabled && !unloadAfterInit && gameInitPromise) {
+ gameInitPromise.then(Engine.unloadEngine);
+ }
+ unloadAfterInit = enabled;
+ };
+
+ this.setStdoutFunc = function(func) {
+
+ var print = function(text) {
+ if (arguments.length > 1) {
+ text = Array.prototype.slice.call(arguments).join(" ");
+ }
+ func(text);
+ };
+ if (this.rtenv)
+ this.rtenv.print = print;
+ stdout = print;
+ };
+
+ this.setStderrFunc = function(func) {
+
+ var printErr = function(text) {
+ if (arguments.length > 1)
+ text = Array.prototype.slice.call(arguments).join(" ");
+ func(text);
+ };
+ if (this.rtenv)
+ this.rtenv.printErr = printErr;
+ stderr = printErr;
+ };
+
+
+ }; // Engine()
+
+ Engine.RuntimeEnvironment = engine.RuntimeEnvironment;
+
+ Engine.initEngine = function(newBasePath) {
+
+ if (newBasePath !== undefined) basePath = getBasePath(newBasePath);
+ if (engineLoadPromise === null) {
+ if (USING_WASM) {
+ if (typeof WebAssembly !== 'object')
+ return Promise.reject(new Error("Browser doesn't support WebAssembly"));
+ // TODO cache/retrieve module to/from idb
+ engineLoadPromise = loadPromise(basePath + '.wasm').then(function(xhr) {
+ return WebAssembly.compile(xhr.response);
+ });
+ } else {
+ var asmjsPromise = loadPromise(basePath + '.asm.js').then(function(xhr) {
+ return asmjsModulePromise(xhr.response);
+ });
+ var memPromise = loadPromise(basePath + '.mem');
+ engineLoadPromise = Promise.all([asmjsPromise, memPromise]).then(function(values) {
+ return { asm: values[0], mem: values[1] };
+ });
+ }
+ engineLoadPromise = engineLoadPromise.catch(function(err) {
+ engineLoadPromise = null;
+ throw err;
+ });
+ }
+ return engineLoadPromise;
+ };
+
+ function asmjsModulePromise(module) {
+ var elem = document.createElement('script');
+ var script = new Blob([
+ 'Engine.asm = (function() { var Module = {};',
+ module,
+ 'return Module.asm; })();'
+ ]);
+ var url = URL.createObjectURL(script);
+ elem.src = url;
+ return new Promise(function(resolve, reject) {
+ elem.addEventListener('load', function() {
+ URL.revokeObjectURL(url);
+ var asm = Engine.asm;
+ Engine.asm = undefined;
+ setTimeout(function() {
+ // delay to reclaim compilation memory
+ resolve(asm);
+ }, 1);
+ });
+ elem.addEventListener('error', function() {
+ URL.revokeObjectURL(url);
+ reject("asm.js faiilure");
+ });
+ document.body.appendChild(elem);
+ });
+ }
+
+ Engine.unloadEngine = function() {
+ engineLoadPromise = null;
+ };
+
+ function loadPromise(file, tracker) {
+ if (tracker === undefined)
+ tracker = loadingFiles;
+ return new Promise(function(resolve, reject) {
+ loadXHR(resolve, reject, file, tracker);
+ });
+ }
+
+ function loadXHR(resolve, reject, file, tracker) {
+
+ var xhr = new XMLHttpRequest;
+ xhr.open('GET', file);
+ if (!file.endsWith('.js')) {
+ xhr.responseType = 'arraybuffer';
+ }
+ ['loadstart', 'progress', 'load', 'error', 'timeout', 'abort'].forEach(function(ev) {
+ xhr.addEventListener(ev, onXHREvent.bind(xhr, resolve, reject, file, tracker));
+ });
+ xhr.send();
+ }
+
+ function onXHREvent(resolve, reject, file, tracker, ev) {
+
+ if (this.status >= 400) {
+
+ if (this.status < 500 || ++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
+ reject(new Error("Failed loading file '" + file + "': " + this.statusText));
+ this.abort();
+ return;
+ } else {
+ loadXHR(resolve, reject, file);
+ }
+ }
+
+ switch (ev.type) {
+ case 'loadstart':
+ if (tracker[file] === undefined) {
+ tracker[file] = {
+ total: ev.total,
+ loaded: ev.loaded,
+ attempts: 0,
+ final: false,
+ };
+ }
+ break;
+
+ case 'progress':
+ tracker[file].loaded = ev.loaded;
+ tracker[file].total = ev.total;
+ break;
+
+ case 'load':
+ tracker[file].final = true;
+ resolve(this);
+ break;
+
+ case 'error':
+ case 'timeout':
+ if (++tracker[file].attempts >= DOWNLOAD_ATTEMPTS_MAX) {
+ tracker[file].final = true;
+ reject(new Error("Failed loading file '" + file + "'"));
+ } else {
+ loadXHR(resolve, reject, file);
+ }
+ break;
+
+ case 'abort':
+ tracker[file].final = true;
+ reject(new Error("Loading file '" + file + "' was aborted."));
+ break;
+ }
+ }
+})();
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 5a161dd0ab..4a97bf4c32 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -100,8 +100,8 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
for (int i = 0; i < lines.size(); i++) {
String current_line = lines[i];
- current_line = current_line.replace("$GODOT_TMEM", itos(memory_mb * 1024 * 1024));
- current_line = current_line.replace("$GODOT_BASE", p_name);
+ current_line = current_line.replace("$GODOT_TOTAL_MEMORY", itos(memory_mb * 1024 * 1024));
+ current_line = current_line.replace("$GODOT_BASENAME", p_name);
current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include"));
current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false");
str_export += current_line + "\n";
@@ -114,28 +114,6 @@ void EditorExportPlatformJavaScript::_fix_html(Vector<uint8_t> &p_html, const Re
}
}
-void EditorExportPlatformJavaScript::_fix_fsloader_js(Vector<uint8_t> &p_js, const String &p_pack_name, uint64_t p_pack_size) {
-
- String str_template = String::utf8(reinterpret_cast<const char *>(p_js.ptr()), p_js.size());
- String str_export;
- Vector<String> lines = str_template.split("\n");
- for (int i = 0; i < lines.size(); i++) {
- if (lines[i].find("$GODOT_PACK_NAME") != -1) {
- str_export += lines[i].replace("$GODOT_PACK_NAME", p_pack_name);
- } else if (lines[i].find("$GODOT_PACK_SIZE") != -1) {
- str_export += lines[i].replace("$GODOT_PACK_SIZE", itos(p_pack_size));
- } else {
- str_export += lines[i] + "\n";
- }
- }
-
- CharString cs = str_export.utf8();
- p_js.resize(cs.length());
- for (int i = 0; i < cs.length(); i++) {
- p_js[i] = cs[i];
- }
-}
-
void EditorExportPlatformJavaScript::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
if (p_preset->get("texture_format/s3tc")) {
@@ -286,10 +264,6 @@ Error EditorExportPlatformJavaScript::export_project(const Ref<EditorExportPrese
_fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug);
file = p_path.get_file();
- } else if (file == "godotfs.js") {
-
- _fix_fsloader_js(data, pck_path.get_file(), pack_size);
- file = p_path.get_file().get_basename() + "fs.js";
} else if (file == "godot.js") {
file = p_path.get_file().get_basename() + ".js";
diff --git a/platform/javascript/godot_shell.html b/platform/javascript/godot_shell.html
deleted file mode 100644
index ee7399a129..0000000000
--- a/platform/javascript/godot_shell.html
+++ /dev/null
@@ -1,347 +0,0 @@
-<!DOCTYPE html>
-<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
-<head>
- <meta charset="utf-8" />
- <title></title>
- <style type="text/css">
- body {
- margin: 0;
- border: 0 none;
- padding: 0;
- text-align: center;
- background-color: #222226;
- font-family: 'Droid Sans', Arial, sans-serif;
- }
-
-
- /* Godot Engine default theme style
- * ================================ */
-
- .godot {
- color: #e0e0e0;
- background-color: #3b3943;
- background-image: linear-gradient(to bottom, #403e48, #35333c);
- border: 1px solid #45434e;
- box-shadow: 0 0 1px 1px #2f2d35;
- }
-
- button.godot {
- font-family: 'Droid Sans', Arial, sans-serif; /* override user agent style */
- padding: 1px 5px;
- background-color: #37353f;
- background-image: linear-gradient(to bottom, #413e49, #3a3842);
- border: 1px solid #514f5d;
- border-radius: 1px;
- box-shadow: 0 0 1px 1px #2a2930;
- }
-
- button.godot:hover {
- color: #f0f0f0;
- background-color: #44414e;
- background-image: linear-gradient(to bottom, #494652, #423f4c);
- border: 1px solid #5a5667;
- box-shadow: 0 0 1px 1px #26252b;
- }
-
- button.godot:active {
- color: #fff;
- background-color: #3e3b46;
- background-image: linear-gradient(to bottom, #36343d, #413e49);
- border: 1px solid #4f4c59;
- box-shadow: 0 0 1px 1px #26252b;
- }
-
- button.godot:disabled {
- color: rgba(230, 230, 230, 0.2);
- background-color: #3d3d3d;
- background-image: linear-gradient(to bottom, #434343, #393939);
- border: 1px solid #474747;
- box-shadow: 0 0 1px 1px #2d2b33;
- }
-
-
- /* Canvas / wrapper
- * ================ */
-
- #container {
- display: inline-block; /* scale with canvas */
- vertical-align: top; /* prevent extra height */
- position: relative; /* root for absolutely positioned overlay */
- margin: 0;
- border: 0 none;
- padding: 0;
- background-color: #0c0c0c;
- }
-
- #canvas {
- display: block;
- margin: 0 auto;
- /* canvas must have border and padding set to zero to
- * calculate cursor coordinates correctly */
- border: 0 none;
- padding: 0;
- color: white;
- }
-
- #canvas:focus {
- outline: none;
- }
-
-
- /* Status display
- * ============== */
-
- #status-container {
- position: absolute;
- left: 0;
- top: 0;
- right: 0;
- bottom: 0;
- display: flex;
- justify-content: center;
- align-items: center;
- /* don't consume click events - make children visible explicitly */
- visibility: hidden;
- }
-
- #status {
- line-height: 1.3;
- cursor: pointer;
- visibility: visible;
- padding: 4px 6px;
- }
-
-
- /* Debug output
- * ============ */
-
- #output-panel {
- display: none;
- max-width: 700px;
- font-size: small;
- margin: 6px auto 0;
- padding: 0 4px 4px;
- text-align: left;
- line-height: 2.2;
- }
-
- #output-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
-
- #output-container {
- padding: 6px;
- background-color: #2c2a32;
- box-shadow: inset 0 0 1px 1px #232127;
- color: #bbb;
- }
-
- #output-scroll {
- line-height: 1;
- height: 12em;
- overflow-y: scroll;
- white-space: pre-wrap;
- font-size: small;
- font-family: "Lucida Console", Monaco, monospace;
- }
- </style>
-$GODOT_HEAD_INCLUDE
-</head>
-<body>
- <div id="container">
- <canvas id="canvas" width="640" height="480" tabindex="0" oncontextmenu="event.preventDefault();">
- HTML5 canvas appears to be unsupported in the current browser.<br />
- Please try updating or use a different browser.
- </canvas>
- <div id="status-container">
- <span id="status" class="godot" onclick="this.style.visibility='hidden';">Downloading page...</span>
- </div>
- </div>
- <div id="output-panel" class="godot">
- <div id="output-header">
- Output:
- <button class="godot" type="button" autocomplete="off" onclick="Presentation.clearOutput();">Clear</button>
- </div>
- <div id="output-container"><div id="output-scroll"></div></div>
- </div>
-
- <!-- Scripts -->
- <script type="text/javascript">//<![CDATA[
- var Presentation = (function() {
- var statusElement = document.getElementById("status");
- var canvasElement = document.getElementById("canvas");
-
- var presentation = {
- postRun: [],
- setStatusVisible: function setStatusVisible(visible) {
- statusElement.style.visibility = (visible ? "visible" : "hidden");
- },
- setStatus: function setStatus(text) {
- if (text.length === 0) {
- // emscripten sets empty string as status after "Running..."
- // per timeout, but another status may have been set by then
- if (Presentation.setStatus.lastText === "Running...")
- Presentation.setStatusVisible(false);
- return;
- }
- Presentation.setStatus.lastText = text;
- while (statusElement.lastChild) {
- statusElement.removeChild(statusElement.lastChild);
- }
- var lines = text.split("\n");
- lines.forEach(function(line, index) {
- statusElement.appendChild(document.createTextNode(line));
- statusElement.appendChild(document.createElement("br"));
- });
- var closeNote = document.createElement("span");
- closeNote.style.fontSize = "small";
- closeNote.textContent = "click to close";
- statusElement.appendChild(closeNote);
- Presentation.setStatusVisible(true);
- },
- isWebGL2Available: function isWebGL2Available() {
- var context;
- try {
- context = canvasElement.getContext("webgl2") || canvasElement.getContext("experimental-webgl2");
- } catch (e) {}
- return !!context;
- },
- };
-
- window.onerror = function(event) { presentation.setStatus("Failure during start-up\nSee JavaScript console") };
-
- if ($GODOT_DEBUG_ENABLED) { // debugging enabled
- var outputRoot = document.getElementById("output-panel");
- var outputElement = document.getElementById("output-scroll");
- const maxOutputMessages = 400;
-
- presentation.setOutputVisible = function setOutputVisible(visible) {
- outputRoot.style.display = (visible ? "block" : "none");
- };
- presentation.clearOutput = function clearOutput() {
- while (outputElement.firstChild) {
- outputElement.firstChild.remove();
- }
- };
-
- presentation.setOutputVisible(true);
-
- presentation.print = function print(text) {
- if (arguments.length > 1) {
- text = Array.prototype.slice.call(arguments).join(" ");
- }
- if (text.length <= 0) return;
- while (outputElement.childElementCount >= maxOutputMessages) {
- outputElement.firstChild.remove();
- }
- var msg = document.createElement("div");
- if (String.prototype.trim.call(text).startsWith("**ERROR**")
- || String.prototype.trim.call(text).startsWith("**EXCEPTION**")) {
- msg.style.color = "#d44";
- } else if (String.prototype.trim.call(text).startsWith("**WARNING**")) {
- msg.style.color = "#ccc000";
- } else if (String.prototype.trim.call(text).startsWith("**SCRIPT ERROR**")) {
- msg.style.color = "#c6d";
- }
- msg.textContent = text;
- var scrollToBottom = outputElement.scrollHeight - (outputElement.clientHeight + outputElement.scrollTop) < 10;
- outputElement.appendChild(msg);
- if (scrollToBottom) {
- outputElement.scrollTop = outputElement.scrollHeight;
- }
- };
-
- presentation.postRun.push(function() {
- window.onerror = function(event) { presentation.print("**EXCEPTION**:", event) };
- });
-
- } else {
- presentation.postRun.push(function() { window.onerror = null; });
- }
-
- return presentation;
- })();
-
- // Emscripten interface
- var Module = (function() {
- const BASE_NAME = '$GODOT_BASE';
- var module = {
- thisProgram: BASE_NAME,
- wasmBinaryFile: BASE_NAME + '.wasm',
- TOTAL_MEMORY: $GODOT_TMEM,
- print: function print(text) {
- if (arguments.length > 1) {
- text = Array.prototype.slice.call(arguments).join(" ");
- }
- console.log(text);
- if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") {
- Presentation.print(text);
- }
- },
- printErr: function printErr(text) {
- if (arguments.length > 1) {
- text = Array.prototype.slice.call(arguments).join(" ");
- }
- console.error(text);
- if (typeof Presentation !== "undefined" && typeof Presentation.print === "function") {
- Presentation.print("**ERROR**:", text)
- }
- },
- canvas: document.getElementById("canvas"),
- setStatus: function setStatus(text) {
- var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
- var now = Date.now();
- if (m) {
- if (now - Date.now() < 30) // if this is a progress update, skip it if too soon
- return;
- text = m[1];
- }
- if (typeof Presentation !== "undefined" && typeof Presentation.setStatus == "function") {
- Presentation.setStatus(text);
- }
- }
- };
-
- // As a default initial behavior, pop up an alert when WebGL context is lost. To make your
- // application robust, you may want to override this behavior before shipping!
- // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
- module.canvas.addEventListener("webglcontextlost", function(e) { alert("WebGL context lost. Plase reload the page."); e.preventDefault(); }, false);
-
- if (typeof Presentation !== "undefined" && Presentation.postRun instanceof Array) {
- module.postRun = Presentation.postRun;
- }
-
- return module;
- })();
-
- if (!Presentation.isWebGL2Available()) {
- Presentation.setStatus("WebGL 2 appears to be unsupported.\nPlease update browser and drivers.");
- Presentation.preventLoading = true;
- } else {
- Presentation.setStatus("Downloading...");
- }
-
- if (Presentation.preventLoading) {
- // prevent *fs.js and Emscripten's SCRIPT placeholder from loading any files
- Presentation._XHR_send = XMLHttpRequest.prototype.send;
- XMLHttpRequest.prototype.send = function() {};
- Presentation._Node_appendChild = Node.prototype.appendChild;
- Node.prototype.appendChild = function(node) {
- if (!(node instanceof HTMLScriptElement)) {
- return Presentation._Node_appendChild.call(this, node);
- }
- }
- }
- //]]></script>
- <script type="text/javascript" src="$GODOT_BASEfs.js"></script>
-{{{ SCRIPT }}}
- <script type="text/javascript">
- if (Presentation.preventLoading) {
- XMLHttpRequest.prototype.send = Presentation._XHR_send;
- Node.prototype.appendChild = Presentation._Node_appendChild;
- }
- </script>
-</body>
-</html>
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index ac8d367366..f103035b27 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -172,14 +172,14 @@ static EM_BOOL _mousebutton_callback(int event_type, const EmscriptenMouseEvent
if (!is_canvas_focused()) {
focus_canvas();
}
- mask |= 1 << ev->get_button_index();
- } else if (mask & (1 << ev->get_button_index())) {
- mask &= ~(1 << ev->get_button_index());
+ mask |= ev->get_button_index();
+ } else if (mask & ev->get_button_index()) {
+ mask &= ~ev->get_button_index();
} else {
// release event, but press was outside the canvas, so ignore
return false;
}
- ev->set_button_mask(mask >> 1);
+ ev->set_button_mask(mask);
_input->parse_input_event(ev);
// prevent selection dragging
@@ -200,7 +200,7 @@ static EM_BOOL _mousemove_callback(int event_type, const EmscriptenMouseEvent *m
Ref<InputEventMouseMotion> ev;
ev.instance();
dom2godot_mod(mouse_event, ev);
- ev->set_button_mask(input_mask >> 1);
+ ev->set_button_mask(input_mask);
ev->set_position(pos);
ev->set_global_position(ev->get_position());
@@ -227,7 +227,7 @@ static EM_BOOL _wheel_callback(int event_type, const EmscriptenWheelEvent *wheel
Ref<InputEventMouseButton> ev;
ev.instance();
- ev->set_button_mask(_input->get_mouse_button_mask() >> 1);
+ ev->set_button_mask(_input->get_mouse_button_mask());
ev->set_position(_input->get_mouse_position());
ev->set_global_position(ev->get_position());
@@ -291,7 +291,7 @@ static EM_BOOL _touchpress_callback(int event_type, const EmscriptenTouchEvent *
Ref<InputEventMouseButton> ev_mouse;
ev_mouse.instance();
- ev_mouse->set_button_mask(_input->get_mouse_button_mask() >> 1);
+ ev_mouse->set_button_mask(_input->get_mouse_button_mask());
dom2godot_mod(touch_event, ev_mouse);
const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
@@ -334,7 +334,7 @@ static EM_BOOL _touchmove_callback(int event_type, const EmscriptenTouchEvent *t
Ref<InputEventMouseMotion> ev_mouse;
ev_mouse.instance();
dom2godot_mod(touch_event, ev_mouse);
- ev_mouse->set_button_mask(_input->get_mouse_button_mask() >> 1);
+ ev_mouse->set_button_mask(_input->get_mouse_button_mask());
const EmscriptenTouchPoint &first_touch = touch_event->touches[lowest_id_index];
ev_mouse->set_position(Point2(first_touch.canvasX, first_touch.canvasY));
@@ -464,11 +464,7 @@ void OS_JavaScript::initialize(const VideoMode &p_desired, int p_video_driver, i
print_line("Init Audio");
AudioDriverManager::add_driver(&audio_driver_javascript);
- audio_driver_javascript.set_singleton();
- if (audio_driver_javascript.init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
@@ -976,7 +972,7 @@ String OS_JavaScript::get_joy_guid(int p_device) const {
return input->get_joy_guid_remapped(p_device);
}
-PowerState OS_JavaScript::get_power_state() {
+OS::PowerState OS_JavaScript::get_power_state() {
return power_manager->get_power_state();
}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index f78a3f2768..4c6469cb58 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -165,7 +165,7 @@ public:
virtual String get_joy_guid(int p_device) const;
bool joy_connection_changed(int p_type, const EmscriptenGamepadEvent *p_event);
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
diff --git a/platform/javascript/power_javascript.cpp b/platform/javascript/power_javascript.cpp
index 3d54146595..10964502d4 100644
--- a/platform/javascript/power_javascript.cpp
+++ b/platform/javascript/power_javascript.cpp
@@ -36,12 +36,12 @@ bool PowerJavascript::UpdatePowerInfo() {
return false;
}
-PowerState PowerJavascript::get_power_state() {
+OS::PowerState PowerJavascript::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN");
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -64,7 +64,7 @@ int PowerJavascript::get_power_percent_left() {
}
PowerJavascript::PowerJavascript()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerJavascript::~PowerJavascript() {
diff --git a/platform/javascript/power_javascript.h b/platform/javascript/power_javascript.h
index 834d765557..8454c5d728 100644
--- a/platform/javascript/power_javascript.h
+++ b/platform/javascript/power_javascript.h
@@ -31,13 +31,13 @@
#ifndef PLATFORM_JAVASCRIPT_POWER_JAVASCRIPT_H_
#define PLATFORM_JAVASCRIPT_POWER_JAVASCRIPT_H_
-#include "os/power.h"
+#include "os/os.h"
class PowerJavascript {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool UpdatePowerInfo();
@@ -45,7 +45,7 @@ public:
PowerJavascript();
virtual ~PowerJavascript();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/javascript/pre_asmjs.js b/platform/javascript/pre_asmjs.js
new file mode 100644
index 0000000000..3c497721b6
--- /dev/null
+++ b/platform/javascript/pre_asmjs.js
@@ -0,0 +1,3 @@
+var Engine = {
+ USING_WASM: false,
+ RuntimeEnvironment: function(Module) {
diff --git a/platform/javascript/pre_wasm.js b/platform/javascript/pre_wasm.js
new file mode 100644
index 0000000000..be4383c8c9
--- /dev/null
+++ b/platform/javascript/pre_wasm.js
@@ -0,0 +1,3 @@
+var Engine = {
+ USING_WASM: true,
+ RuntimeEnvironment: function(Module) {
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index 27117c2e8d..5b2de54535 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -3,6 +3,7 @@
Import('env')
files = [
+ 'crash_handler_osx.mm',
'os_osx.mm',
'godot_main_osx.mm',
'audio_driver_osx.cpp',
@@ -12,4 +13,8 @@ files = [
'power_osx.cpp',
]
-env.Program('#bin/godot', files)
+prog = env.Program('#bin/godot', files)
+if (env['target'] == "debug" or env['target'] == "release_debug"):
+ # Build the .dSYM file for atos
+ action = "dsymutil " + File(prog)[0].path + " -o " + File(prog)[0].path + ".dSYM"
+ env.AddPostAction(prog, action)
diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp
index 78c52af201..3b3ba60507 100644
--- a/platform/osx/audio_driver_osx.cpp
+++ b/platform/osx/audio_driver_osx.cpp
@@ -58,14 +58,14 @@ Error AudioDriverOSX::initDevice() {
AudioStreamBasicDescription strdesc;
- // TODO: Implement this
- /*zeromem(&strdesc, sizeof(strdesc));
+ zeromem(&strdesc, sizeof(strdesc));
UInt32 size = sizeof(strdesc);
result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size);
ERR_FAIL_COND_V(result != noErr, FAILED);
switch (strdesc.mChannelsPerFrame) {
case 2: // Stereo
+ case 4: // Surround 3.1
case 6: // Surround 5.1
case 8: // Surround 7.1
channels = strdesc.mChannelsPerFrame;
@@ -75,7 +75,7 @@ Error AudioDriverOSX::initDevice() {
// Unknown number of channels, default to stereo
channels = 2;
break;
- }*/
+ }
mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
@@ -103,7 +103,8 @@ Error AudioDriverOSX::initDevice() {
samples_in.resize(buffer_size);
if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
+ print_line("CoreAudio: detected " + itos(channels) + " channels");
+ print_line("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
}
AURenderCallbackStruct callback;
@@ -242,7 +243,7 @@ int AudioDriverOSX::get_mix_rate() const {
};
AudioDriver::SpeakerMode AudioDriverOSX::get_speaker_mode() const {
- return SPEAKER_MODE_STEREO;
+ return get_speaker_mode_by_total_channels(channels);
};
void AudioDriverOSX::lock() {
diff --git a/platform/osx/crash_handler_osx.h b/platform/osx/crash_handler_osx.h
new file mode 100644
index 0000000000..ff037e6b7a
--- /dev/null
+++ b/platform/osx/crash_handler_osx.h
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* crash_handler_osx.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CRASH_HANDLER_OSX_H
+#define CRASH_HANDLER_OSX_H
+
+class CrashHandler {
+
+ bool disabled;
+
+public:
+ void initialize();
+
+ void disable();
+ bool is_disabled() const { return disabled; };
+
+ CrashHandler();
+ ~CrashHandler();
+};
+
+#endif
diff --git a/platform/osx/crash_handler_osx.mm b/platform/osx/crash_handler_osx.mm
new file mode 100644
index 0000000000..2ed88db309
--- /dev/null
+++ b/platform/osx/crash_handler_osx.mm
@@ -0,0 +1,179 @@
+/*************************************************************************/
+/* crash_handler_osx.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "main/main.h"
+#include "os_osx.h"
+
+#include <string.h>
+#include <unistd.h>
+
+// Note: Dump backtrace in 32bit mode is getting a bus error on the fgets by the ->execute, so enable only on 64bit
+#if defined(DEBUG_ENABLED) && defined(__x86_64__)
+#define CRASH_HANDLER_ENABLED 1
+#endif
+
+#ifdef CRASH_HANDLER_ENABLED
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stdlib.h>
+
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+
+#ifdef __x86_64__
+static uint64_t load_address() {
+ const struct segment_command_64 *cmd = getsegbyname("__TEXT");
+#else
+static uint32_t load_address() {
+ const struct segment_command *cmd = getsegbyname("__TEXT");
+#endif
+ char full_path[1024];
+ uint32_t size = sizeof(full_path);
+
+ if (cmd && !_NSGetExecutablePath(full_path, &size)) {
+ uint32_t dyld_count = _dyld_image_count();
+ for (uint32_t i = 0; i < dyld_count; i++) {
+ const char *image_name = _dyld_get_image_name(i);
+ if (image_name && strncmp(image_name, full_path, 1024) == 0) {
+ return cmd->vmaddr + _dyld_get_image_vmaddr_slide(i);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void handle_crash(int sig) {
+ if (OS::get_singleton() == NULL)
+ return;
+
+ void *bt_buffer[256];
+ size_t size = backtrace(bt_buffer, 256);
+ String _execpath = OS::get_singleton()->get_executable_path();
+ String msg = GLOBAL_GET("debug/settings/crash_handler/message");
+
+ // Dump the backtrace to stderr with a message to the user
+ fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
+ fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ char **strings = backtrace_symbols(bt_buffer, size);
+ if (strings) {
+ void *load_addr = (void *)load_address();
+
+ for (int i = 1; i < size; i++) {
+ char fname[1024];
+ Dl_info info;
+
+ snprintf(fname, 1024, "%s", strings[i]);
+
+ // Try to demangle the function name to provide a more readable one
+ if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
+ if (info.dli_sname[0] == '_') {
+ int status;
+ char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
+
+ if (status == 0 && demangled) {
+ snprintf(fname, 1024, "%s", demangled);
+ }
+
+ if (demangled)
+ free(demangled);
+ }
+ }
+
+ String output = fname;
+
+ // Try to get the file/line number using atos
+ if (bt_buffer[i] > (void *)0x0 && OS::get_singleton()) {
+ List<String> args;
+ char str[1024];
+
+ args.push_back("-o");
+ args.push_back(_execpath);
+ args.push_back("-arch");
+#ifdef __x86_64__
+ args.push_back("x86_64");
+#else
+ args.push_back("i386");
+#endif
+ args.push_back("-l");
+ snprintf(str, 1024, "%p", load_addr);
+ args.push_back(str);
+ snprintf(str, 1024, "%p", bt_buffer[i]);
+ args.push_back(str);
+
+ int ret;
+ String out = "";
+ Error err = OS::get_singleton()->execute(String("atos"), args, true, NULL, &out, &ret);
+ if (err == OK && out.substr(0, 2) != "0x") {
+ out.erase(out.length() - 1, 1);
+ output = out;
+ }
+ }
+
+ fprintf(stderr, "[%d] %ls\n", i, output.c_str());
+ }
+
+ free(strings);
+ }
+ fprintf(stderr, "-- END OF BACKTRACE --\n");
+
+ // Abort to pass the error to the OS
+ abort();
+}
+#endif
+
+CrashHandler::CrashHandler() {
+ disabled = false;
+}
+
+CrashHandler::~CrashHandler() {
+}
+
+void CrashHandler::disable() {
+ if (disabled)
+ return;
+
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, NULL);
+ signal(SIGFPE, NULL);
+ signal(SIGILL, NULL);
+#endif
+
+ disabled = true;
+}
+
+void CrashHandler::initialize() {
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, handle_crash);
+ signal(SIGFPE, handle_crash);
+ signal(SIGILL, handle_crash);
+#endif
+}
diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h
index c988dfe425..9a7773f5ee 100644
--- a/platform/osx/dir_access_osx.h
+++ b/platform/osx/dir_access_osx.h
@@ -46,6 +46,9 @@
class DirAccessOSX : public DirAccessUnix {
protected:
virtual String fix_unicode_name(const char *p_name) const;
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
};
#endif //UNIX ENABLED
diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm
index 6e8ceb5e19..6121e6ccfb 100644
--- a/platform/osx/dir_access_osx.mm
+++ b/platform/osx/dir_access_osx.mm
@@ -33,7 +33,8 @@
#include <errno.h>
-#include <Foundation/NSString.h>
+#include <AppKit/NSWorkspace.h>
+#include <Foundation/Foundation.h>
String DirAccessOSX::fix_unicode_name(const char *p_name) const {
@@ -45,4 +46,19 @@ String DirAccessOSX::fix_unicode_name(const char *p_name) const {
return fname;
}
+int DirAccessOSX::get_drive_count() {
+ NSArray *vols = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths];
+ return [vols count];
+}
+
+String DirAccessOSX::get_drive(int p_drive) {
+ NSArray *vols = [[NSWorkspace sharedWorkspace] mountedLocalVolumePaths];
+ int count = [vols count];
+
+ ERR_FAIL_INDEX_V(p_drive, count, "");
+
+ NSString *path = vols[p_drive];
+ return String([path UTF8String]);
+}
+
#endif //posix_enabled
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 7f749030ec..2ec76fe0dd 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -88,8 +88,15 @@ public:
};
void EditorExportPlatformOSX::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) {
-
- // what does this need to do?
+ if (p_preset->get("texture_format/s3tc")) {
+ r_features->push_back("s3tc");
+ }
+ if (p_preset->get("texture_format/etc")) {
+ r_features->push_back("etc");
+ }
+ if (p_preset->get("texture_format/etc2")) {
+ r_features->push_back("etc2");
+ }
}
void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) {
@@ -112,6 +119,10 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), ""));
#endif
+
+ 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"), false));
}
void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data) {
diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm
index 83d782cc2f..e2740fc666 100644
--- a/platform/osx/godot_main_osx.mm
+++ b/platform/osx/godot_main_osx.mm
@@ -35,7 +35,6 @@
#include <unistd.h>
int main(int argc, char **argv) {
-
int first_arg = 1;
const char *dbg_arg = "-NSDocumentRevisionsDebugMode";
printf("arguments\n");
@@ -74,6 +73,13 @@ int main(int argc, char **argv) {
}
}
+#ifdef DEBUG_ENABLED
+ // lets report the path we made current after all that
+ char cwd[4096];
+ getcwd(cwd, 4096);
+ printf("Current path: %s\n", cwd);
+#endif
+
OS_OSX os;
Error err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]);
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index ebaebd84ce..c6a9aeba88 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -30,6 +30,7 @@
#ifndef OS_OSX_H
#define OS_OSX_H
+#include "crash_handler_osx.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/unix/os_unix.h"
@@ -110,6 +111,8 @@ public:
power_osx *power_manager;
+ CrashHandler crash_handler;
+
float _mouse_scale(float p_scale) {
if (display_scale > 1.0)
return p_scale;
@@ -149,7 +152,7 @@ public:
virtual void set_mouse_show(bool p_show);
virtual void set_mouse_grab(bool p_grab);
virtual bool is_mouse_grab_enabled() const;
- virtual void warp_mouse_pos(const Point2 &p_to);
+ virtual void warp_mouse_position(const Point2 &p_to);
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String &p_title);
@@ -181,6 +184,7 @@ public:
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen = 0) const;
virtual String get_executable_path() const;
+ virtual String get_resource_dir() const;
virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
@@ -212,7 +216,7 @@ public:
virtual void set_ime_position(const Point2 &p_pos);
virtual void set_ime_intermediate_text_callback(ImeCallback p_callback, void *p_inp);
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
@@ -223,6 +227,9 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
+ void disable_crash_handler();
+ bool is_disable_crash_handler() const;
+
OS_OSX();
};
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index f502fb9a9c..da7321d72a 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -910,6 +910,8 @@ OS::VideoMode OS_OSX::get_default_video_mode() const {
void OS_OSX::initialize_core() {
+ crash_handler.initialize();
+
OS_Unix::initialize_core();
DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES);
@@ -1086,12 +1088,7 @@ void OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
visual_server->init();
// visual_server->cursor_set_visible(false, 0);
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
//
physics_server = memnew(PhysicsServerSW);
@@ -1243,7 +1240,7 @@ bool OS_OSX::is_mouse_grab_enabled() const {
return mouse_grab;
}
-void OS_OSX::warp_mouse_pos(const Point2 &p_to) {
+void OS_OSX::warp_mouse_position(const Point2 &p_to) {
//copied from windows impl with osx native calls
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -1736,6 +1733,17 @@ String OS_OSX::get_executable_path() const {
}
}
+String OS_OSX::get_resource_dir() const {
+ // start with our executable path
+ String path = get_executable_path();
+
+ int pos = path.find_last("/Contents/MacOS/");
+ if (pos < 0)
+ return OS::get_resource_dir();
+
+ return path.substr(0, pos) + "/Contents/Resources/";
+}
+
// Returns string representation of keys, if they are printable.
//
static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
@@ -1901,7 +1909,7 @@ String OS_OSX::get_joy_guid(int p_device) const {
return input->get_joy_guid_remapped(p_device);
}
-PowerState OS_OSX::get_power_state() {
+OS::PowerState OS_OSX::get_power_state() {
return power_manager->get_power_state();
}
@@ -2011,3 +2019,11 @@ OS_OSX::OS_OSX() {
bool OS_OSX::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
+
+void OS_OSX::disable_crash_handler() {
+ crash_handler.disable();
+}
+
+bool OS_OSX::is_disable_crash_handler() const {
+ return crash_handler.is_disabled();
+}
diff --git a/platform/osx/power_osx.cpp b/platform/osx/power_osx.cpp
index 5f3938cb91..eed03e63c1 100644
--- a/platform/osx/power_osx.cpp
+++ b/platform/osx/power_osx.cpp
@@ -174,7 +174,7 @@ bool power_osx::GetPowerInfo_MacOSX() {
nsecs_left = -1;
percent_left = -1;
- power_state = POWERSTATE_UNKNOWN;
+ power_state = OS::POWERSTATE_UNKNOWN;
if (blob != NULL) {
CFArrayRef list = IOPSCopyPowerSourcesList(blob);
@@ -194,13 +194,13 @@ bool power_osx::GetPowerInfo_MacOSX() {
}
if (!have_battery) {
- power_state = POWERSTATE_NO_BATTERY;
+ power_state = OS::POWERSTATE_NO_BATTERY;
} else if (charging) {
- power_state = POWERSTATE_CHARGING;
+ power_state = OS::POWERSTATE_CHARGING;
} else if (have_ac) {
- power_state = POWERSTATE_CHARGED;
+ power_state = OS::POWERSTATE_CHARGED;
} else {
- power_state = POWERSTATE_ON_BATTERY;
+ power_state = OS::POWERSTATE_ON_BATTERY;
}
CFRelease(list);
@@ -218,11 +218,11 @@ bool power_osx::UpdatePowerInfo() {
return false;
}
-PowerState power_osx::get_power_state() {
+OS::PowerState power_osx::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -243,7 +243,7 @@ int power_osx::get_power_percent_left() {
}
power_osx::power_osx()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
power_osx::~power_osx() {
diff --git a/platform/osx/power_osx.h b/platform/osx/power_osx.h
index 692c850d7c..20e47e9cd9 100644
--- a/platform/osx/power_osx.h
+++ b/platform/osx/power_osx.h
@@ -33,7 +33,7 @@
#include "dir_access_osx.h"
#include "os/file_access.h"
-#include "os/power.h"
+#include "os/os.h"
#include <CoreFoundation/CoreFoundation.h>
class power_osx {
@@ -41,7 +41,7 @@ class power_osx {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
void checkps(CFDictionaryRef dict, bool *have_ac, bool *have_battery, bool *charging);
bool GetPowerInfo_MacOSX(/*PowerState * state, int *seconds, int *percent*/);
bool UpdatePowerInfo();
@@ -50,7 +50,7 @@ public:
power_osx();
virtual ~power_osx();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 44034e815d..300c5cffcc 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -62,12 +62,7 @@ void OS_Server::initialize(const VideoMode &p_desired, int p_video_driver, int p
//visual_server = memnew( VisualServerRaster(rasterizer) );
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
sample_manager = memnew(SampleManagerMallocSW);
audio_server = memnew(AudioServerSW(sample_manager));
@@ -200,7 +195,7 @@ void OS_Server::move_window_to_foreground() {
void OS_Server::set_cursor_shape(CursorShape p_shape) {
}
-PowerState OS_Server::get_power_state() {
+OS::PowerState OS_Server::get_power_state() {
return power_manager->get_power_state();
}
@@ -232,7 +227,6 @@ void OS_Server::run() {
OS_Server::OS_Server() {
- AudioDriverManager::add_driver(&driver_dummy);
//adriver here
grab = false;
};
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index f3db053be3..ba12f649be 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -34,7 +34,6 @@
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/unix/os_unix.h"
#include "main/input_default.h"
-#include "servers/audio/audio_driver_dummy.h"
#include "servers/audio_server.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/physics_server.h"
@@ -55,7 +54,6 @@ class OS_Server : public OS_Unix {
List<String> args;
MainLoop *main_loop;
- AudioDriverDummy driver_dummy;
bool grab;
PhysicsServer *physics_server;
@@ -106,7 +104,7 @@ public:
void run();
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index a2be126c58..d66bcaa91c 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -466,14 +466,12 @@ void AppxPackager::add_file(String p_file_name, const uint8_t *p_buffer, size_t
EditorNode::progress_task_step(progress_task, "File: " + p_file_name, (p_file_no * 100) / p_total_files);
}
- bool do_hash = p_file_name != "AppxSignature.p7x";
-
FileMeta meta;
meta.name = p_file_name;
meta.uncompressed_size = p_len;
meta.compressed_size = p_len;
meta.compressed = p_compress;
- meta.zip_offset = package->get_pos();
+ meta.zip_offset = package->get_position();
Vector<uint8_t> file_buffer;
@@ -621,11 +619,11 @@ void AppxPackager::finish() {
// Write central directory
EditorNode::progress_task_step("export", "Finishing package...", 6);
- central_dir_offset = package->get_pos();
+ central_dir_offset = package->get_position();
package->store_buffer(central_dir_data.ptr(), central_dir_data.size());
// End record
- end_of_central_dir_offset = package->get_pos();
+ end_of_central_dir_offset = package->get_position();
Vector<uint8_t> end_record = make_end_of_central_record();
package->store_buffer(end_record.ptr(), end_record.size());
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 3a8932aae2..b909ccccd6 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -268,12 +268,7 @@ void OSUWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_aud
joypad = ref new JoypadUWP(input);
joypad->register_events();
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
power_manager = memnew(PowerUWP);
@@ -855,7 +850,7 @@ bool OSUWP::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
-PowerState OSUWP::get_power_state() {
+OS::PowerState OSUWP::get_power_state() {
return power_manager->get_power_state();
}
diff --git a/platform/uwp/os_uwp.h b/platform/uwp/os_uwp.h
index 5f36396017..a7a5d32cb9 100644
--- a/platform/uwp/os_uwp.h
+++ b/platform/uwp/os_uwp.h
@@ -259,7 +259,7 @@ public:
void input_event(const Ref<InputEvent> &p_event);
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
diff --git a/platform/uwp/power_uwp.cpp b/platform/uwp/power_uwp.cpp
index 07a726647d..81e97b1391 100644
--- a/platform/uwp/power_uwp.cpp
+++ b/platform/uwp/power_uwp.cpp
@@ -31,7 +31,7 @@
#include "power_uwp.h"
PowerUWP::PowerUWP()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerUWP::~PowerUWP() {
@@ -47,12 +47,12 @@ bool PowerUWP::UpdatePowerInfo() {
return false;
}
-PowerState PowerUWP::get_power_state() {
+OS::PowerState PowerUWP::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
WARN_PRINT("Power management is not implemented on this platform, defaulting to POWERSTATE_UNKNOWN");
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
diff --git a/platform/uwp/power_uwp.h b/platform/uwp/power_uwp.h
index 9a9811a4f5..0c57689c50 100644
--- a/platform/uwp/power_uwp.h
+++ b/platform/uwp/power_uwp.h
@@ -33,14 +33,14 @@
#include "os/dir_access.h"
#include "os/file_access.h"
-#include "os/power.h"
+#include "os/os.h"
class PowerUWP {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool UpdatePowerInfo();
@@ -48,7 +48,7 @@ public:
PowerUWP();
virtual ~PowerUWP();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index befbe00183..b56a5c6a80 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -5,6 +5,7 @@ Import('env')
common_win = [
"context_gl_win.cpp",
+ "crash_handler_win.cpp",
"os_windows.cpp",
"ctxgl_procaddr.cpp",
"key_mapping_win.cpp",
@@ -12,7 +13,7 @@ common_win = [
"packet_peer_udp_winsock.cpp",
"stream_peer_winsock.cpp",
"joypad.cpp",
- "power_windows.cpp",
+ "power_windows.cpp",
]
restarget = "godot_res" + env["OBJSUFFIX"]
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 328b987f1f..8640f27699 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -130,24 +130,28 @@ Error ContextGL_Win::initialize() {
0, 0, 0 // Layer Masks Ignored
};
- if (!(hDC = GetDC(hWnd))) {
+ hDC = GetDC(hWnd);
+ if (!hDC) {
MessageBox(NULL, "Can't Create A GL Device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return ERR_CANT_CREATE; // Return FALSE
}
- if (!(pixel_format = ChoosePixelFormat(hDC, &pfd))) // Did Windows Find A Matching Pixel Format?
+ pixel_format = ChoosePixelFormat(hDC, &pfd);
+ if (!pixel_format) // Did Windows Find A Matching Pixel Format?
{
MessageBox(NULL, "Can't Find A Suitable pixel_format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return ERR_CANT_CREATE; // Return FALSE
}
- if (!SetPixelFormat(hDC, pixel_format, &pfd)) // Are We Able To Set The Pixel Format?
+ BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd);
+ if (!ret) // Are We Able To Set The Pixel Format?
{
MessageBox(NULL, "Can't Set The pixel_format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return ERR_CANT_CREATE; // Return FALSE
}
- if (!(hRC = wglCreateContext(hDC))) // Are We Able To Get A Rendering Context?
+ hRC = wglCreateContext(hDC);
+ if (!hRC) // Are We Able To Get A Rendering Context?
{
MessageBox(NULL, "Can't Create A Temporary GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return ERR_CANT_CREATE; // Return FALSE
@@ -175,8 +179,8 @@ Error ContextGL_Win::initialize() {
return ERR_CANT_CREATE;
}
- HGLRC new_hRC;
- if (!(new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs))) {
+ HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
+ if (!new_hRC) {
wglDeleteContext(hRC);
MessageBox(NULL, "Can't Create An OpenGL 3.3 Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return ERR_CANT_CREATE; // Return false
diff --git a/platform/windows/crash_handler_win.cpp b/platform/windows/crash_handler_win.cpp
new file mode 100644
index 0000000000..2f5ee7956e
--- /dev/null
+++ b/platform/windows/crash_handler_win.cpp
@@ -0,0 +1,211 @@
+/*************************************************************************/
+/* crash_handler_win.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#include "main/main.h"
+#include "os_windows.h"
+
+#ifdef CRASH_HANDLER_EXCEPTION
+
+// Backtrace code code based on: https://stackoverflow.com/questions/6205981/windows-c-stack-trace-from-a-running-app
+
+#include <psapi.h>
+#include <algorithm>
+#include <iterator>
+
+#pragma comment(lib, "psapi.lib")
+#pragma comment(lib, "dbghelp.lib")
+
+// Some versions of imagehlp.dll lack the proper packing directives themselves
+// so we need to do it.
+#pragma pack(push, before_imagehlp, 8)
+#include <imagehlp.h>
+#pragma pack(pop, before_imagehlp)
+
+struct module_data {
+ std::string image_name;
+ std::string module_name;
+ void *base_address;
+ DWORD load_size;
+};
+
+class symbol {
+ typedef IMAGEHLP_SYMBOL64 sym_type;
+ sym_type *sym;
+ static const int max_name_len = 1024;
+
+public:
+ symbol(HANDLE process, DWORD64 address)
+ : sym((sym_type *)::operator new(sizeof(*sym) + max_name_len)) {
+ memset(sym, '\0', sizeof(*sym) + max_name_len);
+ sym->SizeOfStruct = sizeof(*sym);
+ sym->MaxNameLength = max_name_len;
+ DWORD64 displacement;
+
+ SymGetSymFromAddr64(process, address, &displacement, sym);
+ }
+
+ std::string name() { return std::string(sym->Name); }
+ std::string undecorated_name() {
+ if (*sym->Name == '\0')
+ return "<couldn't map PC to fn name>";
+ std::vector<char> und_name(max_name_len);
+ UnDecorateSymbolName(sym->Name, &und_name[0], max_name_len, UNDNAME_COMPLETE);
+ return std::string(&und_name[0], strlen(&und_name[0]));
+ }
+};
+
+class get_mod_info {
+ HANDLE process;
+
+public:
+ get_mod_info(HANDLE h)
+ : process(h) {}
+
+ module_data operator()(HMODULE module) {
+ module_data ret;
+ char temp[4096];
+ MODULEINFO mi;
+
+ GetModuleInformation(process, module, &mi, sizeof(mi));
+ ret.base_address = mi.lpBaseOfDll;
+ ret.load_size = mi.SizeOfImage;
+
+ GetModuleFileNameEx(process, module, temp, sizeof(temp));
+ ret.image_name = temp;
+ GetModuleBaseName(process, module, temp, sizeof(temp));
+ ret.module_name = temp;
+ std::vector<char> img(ret.image_name.begin(), ret.image_name.end());
+ std::vector<char> mod(ret.module_name.begin(), ret.module_name.end());
+ SymLoadModule64(process, 0, &img[0], &mod[0], (DWORD64)ret.base_address, ret.load_size);
+ return ret;
+ }
+};
+
+DWORD CrashHandlerException(EXCEPTION_POINTERS *ep) {
+ HANDLE process = GetCurrentProcess();
+ HANDLE hThread = GetCurrentThread();
+ DWORD offset_from_symbol = 0;
+ IMAGEHLP_LINE64 line = { 0 };
+ std::vector<module_data> modules;
+ DWORD cbNeeded;
+ std::vector<HMODULE> module_handles(1);
+
+ if (OS::get_singleton() == NULL || OS::get_singleton()->is_disable_crash_handler() || IsDebuggerPresent()) {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+
+ fprintf(stderr, "%s: Program crashed\n", __FUNCTION__);
+
+ // Load the symbols:
+ if (!SymInitialize(process, NULL, false))
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ SymSetOptions(SymGetOptions() | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME);
+ EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
+ module_handles.resize(cbNeeded / sizeof(HMODULE));
+ EnumProcessModules(process, &module_handles[0], module_handles.size() * sizeof(HMODULE), &cbNeeded);
+ std::transform(module_handles.begin(), module_handles.end(), std::back_inserter(modules), get_mod_info(process));
+ void *base = modules[0].base_address;
+
+ // Setup stuff:
+ CONTEXT *context = ep->ContextRecord;
+ STACKFRAME64 frame;
+ bool skip_first = false;
+
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrStack.Mode = AddrModeFlat;
+ frame.AddrFrame.Mode = AddrModeFlat;
+
+#ifdef _M_X64
+ frame.AddrPC.Offset = context->Rip;
+ frame.AddrStack.Offset = context->Rsp;
+ frame.AddrFrame.Offset = context->Rbp;
+#else
+ frame.AddrPC.Offset = context->Eip;
+ frame.AddrStack.Offset = context->Esp;
+ frame.AddrFrame.Offset = context->Ebp;
+
+ // Skip the first one to avoid a duplicate on 32-bit mode
+ skip_first = true;
+#endif
+
+ line.SizeOfStruct = sizeof(line);
+ IMAGE_NT_HEADERS *h = ImageNtHeader(base);
+ DWORD image_type = h->FileHeader.Machine;
+ int n = 0;
+ String msg = GLOBAL_GET("debug/settings/crash_handler/message");
+
+ fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+
+ do {
+ if (skip_first) {
+ skip_first = false;
+ } else {
+ if (frame.AddrPC.Offset != 0) {
+ std::string fnName = symbol(process, frame.AddrPC.Offset).undecorated_name();
+
+ if (SymGetLineFromAddr64(process, frame.AddrPC.Offset, &offset_from_symbol, &line))
+ fprintf(stderr, "[%d] %s (%s:%d)\n", n, fnName.c_str(), line.FileName, line.LineNumber);
+ else
+ fprintf(stderr, "[%d] %s\n", n, fnName.c_str());
+ } else
+ fprintf(stderr, "[%d] ???\n", n);
+
+ n++;
+ }
+
+ if (!StackWalk64(image_type, process, hThread, &frame, context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
+ break;
+ } while (frame.AddrReturn.Offset != 0 && n < 256);
+
+ fprintf(stderr, "-- END OF BACKTRACE --\n");
+
+ SymCleanup(process);
+
+ // Pass the exception to the OS
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+#endif
+
+CrashHandler::CrashHandler() {
+ disabled = false;
+}
+
+CrashHandler::~CrashHandler() {
+}
+
+void CrashHandler::disable() {
+ if (disabled)
+ return;
+
+ disabled = true;
+}
+
+void CrashHandler::initialize() {
+}
diff --git a/platform/windows/crash_handler_win.h b/platform/windows/crash_handler_win.h
new file mode 100644
index 0000000000..0b1889e4fe
--- /dev/null
+++ b/platform/windows/crash_handler_win.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* crash_handler_win.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CRASH_HANDLER_WIN_H
+#define CRASH_HANDLER_WIN_H
+
+#include <windows.h>
+
+// Crash handler exception only enabled with MSVC
+#if defined(DEBUG_ENABLED) && defined(MSVC)
+#define CRASH_HANDLER_EXCEPTION 1
+
+extern DWORD CrashHandlerException(EXCEPTION_POINTERS *ep);
+#endif
+
+class CrashHandler {
+
+ bool disabled;
+
+public:
+ void initialize();
+
+ void disable();
+ bool is_disabled() const { return disabled; };
+
+ CrashHandler();
+ ~CrashHandler();
+};
+
+#endif
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index d239ccf7d2..5bd9a78f49 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -123,7 +123,7 @@ def configure(env):
env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
elif (env["target"] == "debug"):
- env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od'])
+ env.Append(CCFLAGS=['/Z7', '/DDEBUG_ENABLED', '/DDEBUG_MEMORY_ENABLED', '/DD3D_DEBUG_INFO', '/Od', '/EHsc'])
env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
env.Append(LINKFLAGS=['/DEBUG'])
@@ -226,10 +226,13 @@ def configure(env):
else:
env["PROGSUFFIX"] = env["PROGSUFFIX"] + ".exe" # for linux cross-compilation
- mingw_prefix = ""
-
if (env["bits"] == "default"):
- env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32"
+ if (os.name == "nt"):
+ env["bits"] = "64" if "PROGRAMFILES(X86)" in os.environ else "32"
+ else: # default to 64-bit on Linux
+ env["bits"] = "64"
+
+ mingw_prefix = ""
if (env["bits"] == "32"):
env.Append(LINKFLAGS=['-static'])
diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp
index d2ac6ecb50..cff2cbad42 100644
--- a/platform/windows/godot_win.cpp
+++ b/platform/windows/godot_win.cpp
@@ -156,10 +156,7 @@ int widechar_main(int argc, wchar_t **argv) {
return os.get_exit_code();
};
-int main(int _argc, char **_argv) {
- // _argc and _argv are ignored
- // we are going to use the WideChar version of them instead
-
+int _main() {
LPWSTR *wc_argv;
int argc;
int result;
@@ -177,6 +174,21 @@ int main(int _argc, char **_argv) {
return result;
}
+int main(int _argc, char **_argv) {
+// _argc and _argv are ignored
+// we are going to use the WideChar version of them instead
+
+#ifdef CRASH_HANDLER_EXCEPTION
+ __try {
+ return _main();
+ } __except (CrashHandlerException(GetExceptionInformation())) {
+ return 1;
+ }
+#else
+ return _main();
+#endif
+}
+
HINSTANCE godot_hinstance = NULL;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
diff --git a/platform/windows/joypad.cpp b/platform/windows/joypad.cpp
index 00cfa812de..0c7358f499 100644
--- a/platform/windows/joypad.cpp
+++ b/platform/windows/joypad.cpp
@@ -379,7 +379,9 @@ void JoypadWindows::process_joypads() {
IDirectInputDevice8_Acquire(joy->di_joy);
joy->di_joy->Poll();
}
- if (FAILED(hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js))) {
+
+ hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js);
+ if (FAILED(hr)) {
//printf("failed to read joy #%d\n", i);
continue;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index deb9c25576..db7cd0b938 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -164,6 +164,8 @@ const char *OS_Windows::get_audio_driver_name(int p_driver) const {
void OS_Windows::initialize_core() {
+ crash_handler.initialize();
+
last_button_state = 0;
//RedirectIOToConsole();
@@ -887,6 +889,12 @@ static int QueryDpiForMonitor(HMONITOR hmon, _MonitorDpiType dpiType = MDT_Defau
return (dpiX + dpiY) / 2;
}
+typedef enum _SHC_PROCESS_DPI_AWARENESS {
+ SHC_PROCESS_DPI_UNAWARE = 0,
+ SHC_PROCESS_SYSTEM_DPI_AWARE = 1,
+ SHC_PROCESS_PER_MONITOR_DPI_AWARE = 2
+} SHC_PROCESS_DPI_AWARENESS;
+
void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
main_loop = NULL;
@@ -894,6 +902,20 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
window_has_focus = true;
WNDCLASSEXW wc;
+ if (is_hidpi_allowed()) {
+ HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
+
+ if (Shcore != NULL) {
+ typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(SHC_PROCESS_DPI_AWARENESS);
+
+ SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)GetProcAddress(Shcore, "SetProcessDpiAwareness");
+
+ if (SetProcessDpiAwareness) {
+ SetProcessDpiAwareness(SHC_PROCESS_SYSTEM_DPI_AWARE);
+ }
+ }
+ }
+
video_mode = p_desired;
//printf("**************** desired %s, mode %s\n", p_desired.fullscreen?"true":"false", video_mode.fullscreen?"true":"false");
RECT WindowRect;
@@ -996,7 +1018,16 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
video_mode.fullscreen = false;
} else {
- if (!(hWnd = CreateWindowExW(dwExStyle, L"Engine", L"", dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2, (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, NULL, NULL, hInstance, NULL))) {
+ hWnd = CreateWindowExW(
+ dwExStyle,
+ L"Engine", L"",
+ dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+ (GetSystemMetrics(SM_CXSCREEN) - WindowRect.right) / 2,
+ (GetSystemMetrics(SM_CYSCREEN) - WindowRect.bottom) / 2,
+ WindowRect.right - WindowRect.left,
+ WindowRect.bottom - WindowRect.top,
+ NULL, NULL, hInstance, NULL);
+ if (!hWnd) {
MessageBoxW(NULL, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
return; // Return FALSE
}
@@ -1050,12 +1081,7 @@ void OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
power_manager = memnew(PowerWindows);
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- ERR_PRINT("Initializing audio failed.");
- }
+ AudioDriverManager::initialize(p_audio_driver);
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
@@ -1278,7 +1304,7 @@ OS_Windows::MouseMode OS_Windows::get_mouse_mode() const {
return mouse_mode;
}
-void OS_Windows::warp_mouse_pos(const Point2 &p_to) {
+void OS_Windows::warp_mouse_position(const Point2 &p_to) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -2322,7 +2348,7 @@ bool OS_Windows::is_vsync_enabled() const {
return true;
}
-PowerState OS_Windows::get_power_state() {
+OS::PowerState OS_Windows::get_power_state() {
return power_manager->get_power_state();
}
@@ -2339,6 +2365,14 @@ bool OS_Windows::_check_internal_feature_support(const String &p_feature) {
return p_feature == "pc" || p_feature == "s3tc";
}
+void OS_Windows::disable_crash_handler() {
+ crash_handler.disable();
+}
+
+bool OS_Windows::is_disable_crash_handler() const {
+ return crash_handler.is_disabled();
+}
+
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
key_event_pos = 0;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 0c5965bf51..8a955aa224 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -31,6 +31,7 @@
#define OS_WINDOWS_H
#include "context_gl_win.h"
+#include "crash_handler_win.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
#include "os/input.h"
@@ -134,6 +135,8 @@ class OS_Windows : public OS {
AudioDriverXAudio2 driver_xaudio2;
#endif
+ CrashHandler crash_handler;
+
void _drag_event(int p_x, int p_y, int idx);
void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
@@ -186,7 +189,7 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
- virtual void warp_mouse_pos(const Point2 &p_to);
+ virtual void warp_mouse_position(const Point2 &p_to);
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String &p_title);
@@ -278,12 +281,15 @@ public:
virtual void set_use_vsync(bool p_enable);
virtual bool is_vsync_enabled() const;
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
virtual bool _check_internal_feature_support(const String &p_feature);
+ void disable_crash_handler();
+ bool is_disable_crash_handler() const;
+
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
};
diff --git a/platform/windows/power_windows.cpp b/platform/windows/power_windows.cpp
index b37e189a3a..8d86f160f1 100644
--- a/platform/windows/power_windows.cpp
+++ b/platform/windows/power_windows.cpp
@@ -64,19 +64,19 @@ bool PowerWindows::GetPowerInfo_Windows() {
/* This API should exist back to Win95. */
if (!GetSystemPowerStatus(&status)) {
/* !!! FIXME: push GetLastError() into GetError() */
- power_state = POWERSTATE_UNKNOWN;
+ power_state = OS::POWERSTATE_UNKNOWN;
} else if (status.BatteryFlag == 0xFF) { /* unknown state */
- power_state = POWERSTATE_UNKNOWN;
+ power_state = OS::POWERSTATE_UNKNOWN;
} else if (status.BatteryFlag & (1 << 7)) { /* no battery */
- power_state = POWERSTATE_NO_BATTERY;
+ power_state = OS::POWERSTATE_NO_BATTERY;
} else if (status.BatteryFlag & (1 << 3)) { /* charging */
- power_state = POWERSTATE_CHARGING;
+ power_state = OS::POWERSTATE_CHARGING;
need_details = TRUE;
} else if (status.ACLineStatus == 1) {
- power_state = POWERSTATE_CHARGED; /* on AC, not charging. */
+ power_state = OS::POWERSTATE_CHARGED; /* on AC, not charging. */
need_details = TRUE;
} else {
- power_state = POWERSTATE_ON_BATTERY; /* not on AC. */
+ power_state = OS::POWERSTATE_ON_BATTERY; /* not on AC. */
need_details = TRUE;
}
@@ -97,11 +97,11 @@ bool PowerWindows::GetPowerInfo_Windows() {
return TRUE; /* always the definitive answer on Windows. */
}
-PowerState PowerWindows::get_power_state() {
+OS::PowerState PowerWindows::get_power_state() {
if (GetPowerInfo_Windows()) {
return power_state;
} else {
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
@@ -122,7 +122,7 @@ int PowerWindows::get_power_percent_left() {
}
PowerWindows::PowerWindows()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerWindows::~PowerWindows() {
diff --git a/platform/windows/power_windows.h b/platform/windows/power_windows.h
index 9da9841f48..0745615195 100644
--- a/platform/windows/power_windows.h
+++ b/platform/windows/power_windows.h
@@ -33,7 +33,7 @@
#include "os/dir_access.h"
#include "os/file_access.h"
-#include "os/power.h"
+#include "os/os.h"
#include <windows.h>
@@ -42,7 +42,7 @@ class PowerWindows {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
bool GetPowerInfo_Windows();
@@ -50,7 +50,7 @@ public:
PowerWindows();
virtual ~PowerWindows();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index fc9208c563..62717f3221 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -3,12 +3,13 @@
Import('env')
-common_x11 = [\
- "context_gl_x11.cpp",\
- "os_x11.cpp",\
- "key_mapping_x11.cpp",\
- "joypad_linux.cpp",\
- "power_x11.cpp",\
+common_x11 = [
+ "context_gl_x11.cpp",
+ "crash_handler_x11.cpp",
+ "os_x11.cpp",
+ "key_mapping_x11.cpp",
+ "joypad_linux.cpp",
+ "power_x11.cpp",
]
env.Program('#bin/godot', ['godot_x11.cpp'] + common_x11)
diff --git a/platform/x11/crash_handler_x11.cpp b/platform/x11/crash_handler_x11.cpp
new file mode 100644
index 0000000000..3c54d5cbc2
--- /dev/null
+++ b/platform/x11/crash_handler_x11.cpp
@@ -0,0 +1,136 @@
+/*************************************************************************/
+/* crash_handler_x11.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifdef DEBUG_ENABLED
+#define CRASH_HANDLER_ENABLED 1
+#endif
+
+#include "main/main.h"
+#include "os_x11.h"
+
+#ifdef CRASH_HANDLER_ENABLED
+#include <cxxabi.h>
+#include <dlfcn.h>
+#include <execinfo.h>
+#include <signal.h>
+#include <stdlib.h>
+
+static void handle_crash(int sig) {
+ if (OS::get_singleton() == NULL)
+ return;
+
+ void *bt_buffer[256];
+ size_t size = backtrace(bt_buffer, 256);
+ String _execpath = OS::get_singleton()->get_executable_path();
+ String msg = GLOBAL_GET("debug/settings/crash_handler/message");
+
+ // Dump the backtrace to stderr with a message to the user
+ fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig);
+ fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str());
+ char **strings = backtrace_symbols(bt_buffer, size);
+ if (strings) {
+ for (size_t i = 1; i < size; i++) {
+ char fname[1024];
+ Dl_info info;
+
+ snprintf(fname, 1024, "%s", strings[i]);
+
+ // Try to demangle the function name to provide a more readable one
+ if (dladdr(bt_buffer[i], &info) && info.dli_sname) {
+ if (info.dli_sname[0] == '_') {
+ int status;
+ char *demangled = abi::__cxa_demangle(info.dli_sname, NULL, 0, &status);
+
+ if (status == 0 && demangled) {
+ snprintf(fname, 1024, "%s", demangled);
+ }
+
+ if (demangled)
+ free(demangled);
+ }
+ }
+
+ List<String> args;
+
+ char str[1024];
+ snprintf(str, 1024, "%p", bt_buffer[i]);
+ args.push_back(str);
+ args.push_back("-e");
+ args.push_back(_execpath);
+
+ String output = "";
+
+ // Try to get the file/line number using addr2line
+ if (OS::get_singleton()) {
+ int ret;
+ Error err = OS::get_singleton()->execute(String("addr2line"), args, true, NULL, &output, &ret);
+ if (err == OK) {
+ output.erase(output.length() - 1, 1);
+ }
+ }
+
+ fprintf(stderr, "[%ld] %s (%ls)\n", i, fname, output.c_str());
+ }
+
+ free(strings);
+ }
+ fprintf(stderr, "-- END OF BACKTRACE --\n");
+
+ // Abort to pass the error to the OS
+ abort();
+}
+#endif
+
+CrashHandler::CrashHandler() {
+ disabled = false;
+}
+
+CrashHandler::~CrashHandler() {
+}
+
+void CrashHandler::disable() {
+ if (disabled)
+ return;
+
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, NULL);
+ signal(SIGFPE, NULL);
+ signal(SIGILL, NULL);
+#endif
+
+ disabled = true;
+}
+
+void CrashHandler::initialize() {
+#ifdef CRASH_HANDLER_ENABLED
+ signal(SIGSEGV, handle_crash);
+ signal(SIGFPE, handle_crash);
+ signal(SIGILL, handle_crash);
+#endif
+}
diff --git a/platform/x11/crash_handler_x11.h b/platform/x11/crash_handler_x11.h
new file mode 100644
index 0000000000..e01334cbf2
--- /dev/null
+++ b/platform/x11/crash_handler_x11.h
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* crash_handler_x11.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+#ifndef CRASH_HANDLER_X11_H
+#define CRASH_HANDLER_X11_H
+
+class CrashHandler {
+
+ bool disabled;
+
+public:
+ void initialize();
+
+ void disable();
+ bool is_disabled() const { return disabled; };
+
+ CrashHandler();
+ ~CrashHandler();
+};
+
+#endif
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index 086681d4a4..d61175da60 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -87,6 +87,7 @@ def configure(env):
elif (env["target"] == "debug"):
env.Prepend(CCFLAGS=['-g2', '-DDEBUG_ENABLED', '-DDEBUG_MEMORY_ENABLED'])
+ env.Append(LINKFLAGS=['-rdynamic'])
## Architecture
diff --git a/platform/x11/export/export.cpp b/platform/x11/export/export.cpp
index 59b1a44247..fdb43c9ae0 100644
--- a/platform/x11/export/export.cpp
+++ b/platform/x11/export/export.cpp
@@ -50,6 +50,7 @@ void register_x11_exporter() {
platform->set_release_64("linux_x11_64_release");
platform->set_debug_64("linux_x11_64_debug");
platform->set_os_name("X11");
+ platform->set_chmod_flags(0755);
EditorExport::get_singleton()->add_export_platform(platform);
}
diff --git a/platform/x11/joypad_linux.cpp b/platform/x11/joypad_linux.cpp
index 3453297716..428385f7cb 100644
--- a/platform/x11/joypad_linux.cpp
+++ b/platform/x11/joypad_linux.cpp
@@ -125,7 +125,6 @@ void JoypadLinux::enumerate_joypads(udev *p_udev) {
enumerate = udev_enumerate_new(p_udev);
udev_enumerate_add_match_subsystem(enumerate, "input");
- udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYPAD", "1");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index 767ede8540..599c0d2278 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -93,6 +93,13 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
return AudioDriverManager::get_driver(p_driver)->get_name();
}
+void OS_X11::initialize_core() {
+
+ crash_handler.initialize();
+
+ OS_Unix::initialize_core();
+}
+
void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver) {
long im_event_mask = 0;
@@ -246,6 +253,11 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
// borderless fullscreen window mode
if (current_videomode.fullscreen) {
+ // set bypass compositor hint
+ Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
+ unsigned long compositing_disable_on = 1;
+ XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
+
// needed for lxde/openbox, possibly others
Hints hints;
Atom property;
@@ -301,29 +313,7 @@ void OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_au
XFree(xsh);
}
- AudioDriverManager::get_driver(p_audio_driver)->set_singleton();
-
- audio_driver_index = p_audio_driver;
- if (AudioDriverManager::get_driver(p_audio_driver)->init() != OK) {
-
- bool success = false;
- audio_driver_index = -1;
- for (int i = 0; i < AudioDriverManager::get_driver_count(); i++) {
- if (i == p_audio_driver)
- continue;
- AudioDriverManager::get_driver(i)->set_singleton();
- if (AudioDriverManager::get_driver(i)->init() == OK) {
- success = true;
- print_line("Audio Driver Failed: " + String(AudioDriverManager::get_driver(p_audio_driver)->get_name()));
- print_line("Using alternate audio driver: " + String(AudioDriverManager::get_driver(i)->get_name()));
- audio_driver_index = i;
- break;
- }
- }
- if (!success) {
- ERR_PRINT("Initializing audio failed.");
- }
- }
+ AudioDriverManager::initialize(p_audio_driver);
ERR_FAIL_COND(!visual_server);
ERR_FAIL_COND(x11_window == 0);
@@ -623,7 +613,7 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
XFlush(x11_display);
}
-void OS_X11::warp_mouse_pos(const Point2 &p_to) {
+void OS_X11::warp_mouse_position(const Point2 &p_to) {
if (mouse_mode == MOUSE_MODE_CAPTURED) {
@@ -695,6 +685,12 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
xev.xclient.data.l[2] = 0;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
+ // set bypass compositor hint
+ Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False);
+ unsigned long compositing_disable_on = p_enabled ? 1 : 0;
+ XChangeProperty(x11_display, x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1);
+
XFlush(x11_display);
if (!p_enabled && !is_window_resizable()) {
@@ -2159,7 +2155,7 @@ void OS_X11::set_context(int p_context) {
}
}
-PowerState OS_X11::get_power_state() {
+OS::PowerState OS_X11::get_power_state() {
return power_manager->get_power_state();
}
@@ -2171,11 +2167,15 @@ int OS_X11::get_power_percent_left() {
return power_manager->get_power_percent_left();
}
-OS_X11::OS_X11() {
+void OS_X11::disable_crash_handler() {
+ crash_handler.disable();
+}
-#ifdef RTAUDIO_ENABLED
- AudioDriverManager::add_driver(&driver_rtaudio);
-#endif
+bool OS_X11::is_disable_crash_handler() const {
+ return crash_handler.is_disabled();
+}
+
+OS_X11::OS_X11() {
#ifdef PULSEAUDIO_ENABLED
AudioDriverManager::add_driver(&driver_pulseaudio);
@@ -2185,11 +2185,6 @@ OS_X11::OS_X11() {
AudioDriverManager::add_driver(&driver_alsa);
#endif
- if (AudioDriverManager::get_driver_count() == 0) {
- WARN_PRINT("No sound driver found... Defaulting to dummy driver");
- AudioDriverManager::add_driver(&driver_dummy);
- }
-
minimized = false;
xim_style = 0L;
mouse_mode = MOUSE_MODE_VISIBLE;
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 51240fa023..a0338dacf1 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -31,17 +31,16 @@
#define OS_X11_H
#include "context_gl_x11.h"
+#include "crash_handler_x11.h"
#include "drivers/unix/os_unix.h"
#include "os/input.h"
#include "servers/visual_server.h"
//#include "servers/visual/visual_server_wrap_mt.h"
#include "drivers/alsa/audio_driver_alsa.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
-#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "joypad_linux.h"
#include "main/input_default.h"
#include "power_x11.h"
-#include "servers/audio/audio_driver_dummy.h"
#include "servers/audio_server.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
@@ -153,10 +152,6 @@ class OS_X11 : public OS_Unix {
JoypadLinux *joypad;
#endif
-#ifdef RTAUDIO_ENABLED
- AudioDriverRtAudio driver_rtaudio;
-#endif
-
#ifdef ALSA_ENABLED
AudioDriverALSA driver_alsa;
#endif
@@ -164,12 +159,13 @@ class OS_X11 : public OS_Unix {
#ifdef PULSEAUDIO_ENABLED
AudioDriverPulseAudio driver_pulseaudio;
#endif
- AudioDriverDummy driver_dummy;
Atom net_wm_icon;
PowerX11 *power_manager;
+ CrashHandler crash_handler;
+
int audio_driver_index;
unsigned int capture_idle;
bool maximized;
@@ -191,6 +187,7 @@ protected:
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
+ virtual void initialize_core();
virtual void initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
virtual void finalize();
@@ -204,7 +201,7 @@ public:
void set_mouse_mode(MouseMode p_mode);
MouseMode get_mouse_mode() const;
- virtual void warp_mouse_pos(const Point2 &p_to);
+ virtual void warp_mouse_position(const Point2 &p_to);
virtual Point2 get_mouse_position() const;
virtual int get_mouse_button_state() const;
virtual void set_window_title(const String &p_title);
@@ -265,7 +262,7 @@ public:
virtual void set_use_vsync(bool p_enable);
virtual bool is_vsync_enabled() const;
- virtual PowerState get_power_state();
+ virtual OS::PowerState get_power_state();
virtual int get_power_seconds_left();
virtual int get_power_percent_left();
@@ -273,6 +270,9 @@ public:
void run();
+ void disable_crash_handler();
+ bool is_disable_crash_handler() const;
+
OS_X11();
};
diff --git a/platform/x11/power_x11.cpp b/platform/x11/power_x11.cpp
index 32100354a6..76ff7f91fb 100644
--- a/platform/x11/power_x11.cpp
+++ b/platform/x11/power_x11.cpp
@@ -252,7 +252,7 @@ bool PowerX11::GetPowerInfo_Linux_proc_acpi() {
this->nsecs_left = -1;
this->percent_left = -1;
- this->power_state = POWERSTATE_UNKNOWN;
+ this->power_state = OS::POWERSTATE_UNKNOWN;
dirp->change_dir(proc_acpi_battery_path);
Error err = dirp->list_dir_begin();
@@ -282,13 +282,13 @@ bool PowerX11::GetPowerInfo_Linux_proc_acpi() {
}
if (!have_battery) {
- this->power_state = POWERSTATE_NO_BATTERY;
+ this->power_state = OS::POWERSTATE_NO_BATTERY;
} else if (charging) {
- this->power_state = POWERSTATE_CHARGING;
+ this->power_state = OS::POWERSTATE_CHARGING;
} else if (have_ac) {
- this->power_state = POWERSTATE_CHARGED;
+ this->power_state = OS::POWERSTATE_CHARGED;
} else {
- this->power_state = POWERSTATE_ON_BATTERY;
+ this->power_state = OS::POWERSTATE_ON_BATTERY;
}
return true; /* definitive answer. */
@@ -400,17 +400,17 @@ bool PowerX11::GetPowerInfo_Linux_proc_apm() {
}
if (battery_flag == 0xFF) { /* unknown state */
- this->power_state = POWERSTATE_UNKNOWN;
+ this->power_state = OS::POWERSTATE_UNKNOWN;
} else if (battery_flag & (1 << 7)) { /* no battery */
- this->power_state = POWERSTATE_NO_BATTERY;
+ this->power_state = OS::POWERSTATE_NO_BATTERY;
} else if (battery_flag & (1 << 3)) { /* charging */
- this->power_state = POWERSTATE_CHARGING;
+ this->power_state = OS::POWERSTATE_CHARGING;
need_details = true;
} else if (ac_status == 1) {
- this->power_state = POWERSTATE_CHARGED; /* on AC, not charging. */
+ this->power_state = OS::POWERSTATE_CHARGED; /* on AC, not charging. */
need_details = true;
} else {
- this->power_state = POWERSTATE_ON_BATTERY;
+ this->power_state = OS::POWERSTATE_ON_BATTERY;
need_details = true;
}
@@ -445,7 +445,7 @@ bool PowerX11::GetPowerInfo_Linux_sys_class_power_supply(/*PowerState *state, in
return false;
}
- this->power_state = POWERSTATE_NO_BATTERY; /* assume we're just plugged in. */
+ this->power_state = OS::POWERSTATE_NO_BATTERY; /* assume we're just plugged in. */
this->nsecs_left = -1;
this->percent_left = -1;
@@ -454,7 +454,7 @@ bool PowerX11::GetPowerInfo_Linux_sys_class_power_supply(/*PowerState *state, in
while (name != "") {
bool choose = false;
char str[64];
- PowerState st;
+ OS::PowerState st;
int secs;
int pct;
@@ -475,17 +475,17 @@ bool PowerX11::GetPowerInfo_Linux_sys_class_power_supply(/*PowerState *state, in
/* some drivers don't offer this, so if it's not explicitly reported assume it's present. */
if (read_power_file(base, name.utf8().get_data(), "present", str, sizeof(str)) && (String(str) == "0\n")) {
- st = POWERSTATE_NO_BATTERY;
+ st = OS::POWERSTATE_NO_BATTERY;
} else if (!read_power_file(base, name.utf8().get_data(), "status", str, sizeof(str))) {
- st = POWERSTATE_UNKNOWN; /* uh oh */
+ st = OS::POWERSTATE_UNKNOWN; /* uh oh */
} else if (String(str) == "Charging\n") {
- st = POWERSTATE_CHARGING;
+ st = OS::POWERSTATE_CHARGING;
} else if (String(str) == "Discharging\n") {
- st = POWERSTATE_ON_BATTERY;
+ st = OS::POWERSTATE_ON_BATTERY;
} else if ((String(str) == "Full\n") || (String(str) == "Not charging\n")) {
- st = POWERSTATE_CHARGED;
+ st = OS::POWERSTATE_CHARGED;
} else {
- st = POWERSTATE_UNKNOWN; /* uh oh */
+ st = OS::POWERSTATE_UNKNOWN; /* uh oh */
}
if (!read_power_file(base, name.utf8().get_data(), "capacity", str, sizeof(str))) {
@@ -543,17 +543,17 @@ bool PowerX11::UpdatePowerInfo() {
}
PowerX11::PowerX11()
- : nsecs_left(-1), percent_left(-1), power_state(POWERSTATE_UNKNOWN) {
+ : nsecs_left(-1), percent_left(-1), power_state(OS::POWERSTATE_UNKNOWN) {
}
PowerX11::~PowerX11() {
}
-PowerState PowerX11::get_power_state() {
+OS::PowerState PowerX11::get_power_state() {
if (UpdatePowerInfo()) {
return power_state;
} else {
- return POWERSTATE_UNKNOWN;
+ return OS::POWERSTATE_UNKNOWN;
}
}
diff --git a/platform/x11/power_x11.h b/platform/x11/power_x11.h
index e34223036d..7fc258bc0d 100644
--- a/platform/x11/power_x11.h
+++ b/platform/x11/power_x11.h
@@ -33,14 +33,14 @@
#include "os/dir_access.h"
#include "os/file_access.h"
-#include "os/power.h"
+#include "os/os.h"
class PowerX11 {
private:
int nsecs_left;
int percent_left;
- PowerState power_state;
+ OS::PowerState power_state;
FileAccessRef open_power_file(const char *base, const char *node, const char *key);
bool read_power_file(const char *base, const char *node, const char *key, char *buf, size_t buflen);
@@ -58,7 +58,7 @@ public:
PowerX11();
virtual ~PowerX11();
- PowerState get_power_state();
+ OS::PowerState get_power_state();
int get_power_seconds_left();
int get_power_percent_left();
};