summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java18
-rw-r--r--platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java4
-rw-r--r--platform/iphone/export/export.cpp8
-rw-r--r--platform/javascript/javascript_main.cpp12
-rw-r--r--platform/linuxbsd/display_server_x11.cpp119
-rw-r--r--platform/linuxbsd/display_server_x11.h6
-rw-r--r--platform/osx/display_server_osx.h6
-rw-r--r--platform/osx/display_server_osx.mm152
-rw-r--r--platform/osx/export/export.cpp125
-rw-r--r--platform/uwp/export/export.cpp22
-rw-r--r--platform/uwp/os_uwp.cpp21
-rw-r--r--platform/windows/display_server_windows.cpp137
-rw-r--r--platform/windows/display_server_windows.h6
-rw-r--r--platform/windows/os_windows.cpp80
-rw-r--r--platform/windows/os_windows.h4
16 files changed, 498 insertions, 224 deletions
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
index 8ba9b0400f..fcbbc86100 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java
@@ -262,7 +262,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe
// Include the returned non-null views in the Godot view hierarchy.
for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) {
- View pluginView = plugin.onMainCreateView(this);
+ View pluginView = plugin.onMainCreate(this);
if (pluginView != null) {
layout.addView(pluginView);
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index 431bd4f5f9..ce85880fa3 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -35,6 +35,7 @@ import org.godotengine.godot.Godot;
import android.app.Activity;
import android.content.Intent;
+import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.View;
@@ -93,6 +94,14 @@ public abstract class GodotPlugin {
}
/**
+ * Provides access to the underlying {@link Activity}.
+ */
+ @Nullable
+ protected Activity getActivity() {
+ return godot;
+ }
+
+ /**
* Register the plugin with Godot native code.
*
* This method is invoked on the render thread.
@@ -145,13 +154,14 @@ public abstract class GodotPlugin {
* Invoked once during the Godot Android initialization process after creation of the
* {@link org.godotengine.godot.GodotView} view.
* <p>
- * This method should be overridden by descendants of this class that would like to add
- * their view/layout to the Godot view hierarchy.
+ * The plugin can return a non-null {@link View} layout in order to add it to the Godot view
+ * hierarchy.
*
- * @return the view to be included; null if no views should be included.
+ * @see Activity#onCreate(Bundle)
+ * @return the plugin's view to be included; null if no views should be included.
*/
@Nullable
- public View onMainCreateView(Activity activity) {
+ public View onMainCreate(Activity activity) {
return null;
}
diff --git a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
index 6447a9ec3f..bf8e485d96 100644
--- a/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
+++ b/platform/android/java/plugins/godotpayment/src/main/java/org/godotengine/godot/plugin/payment/GodotPayment.java
@@ -67,7 +67,7 @@ public class GodotPayment extends GodotPlugin implements PurchasesUpdatedListene
super(godot);
billingClient = BillingClient
- .newBuilder(getGodot())
+ .newBuilder(getActivity())
.enablePendingPurchases()
.setListener(this)
.build();
@@ -182,7 +182,7 @@ public class GodotPayment extends GodotPlugin implements PurchasesUpdatedListene
.setSkuDetails(skuDetails)
.build();
- BillingResult result = billingClient.launchBillingFlow(getGodot(), purchaseParams);
+ BillingResult result = billingClient.launchBillingFlow(getActivity(), purchaseParams);
Dictionary returnValue = new Dictionary();
if (result.getResponseCode() == BillingClient.BillingResponseCode.OK) {
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 63c3cb8c23..aadc60175b 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -217,7 +217,7 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
@@ -293,8 +293,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$name", p_config.pkg_name) + "\n";
} else if (lines[i].find("$info") != -1) {
strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
- } else if (lines[i].find("$identifier") != -1) {
- strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n";
+ } else if (lines[i].find("$bundle_identifier") != -1) {
+ strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
} else if (lines[i].find("$short_version") != -1) {
strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
} else if (lines[i].find("$version") != -1) {
@@ -1346,7 +1346,7 @@ bool EditorExportPlatformIOS::can_export(const Ref<EditorExportPreset> &p_preset
valid = false;
}
- String identifier = p_preset->get("application/identifier");
+ String identifier = p_preset->get("application/bundle_identifier");
String pn_err;
if (!is_package_name_valid(identifier, &pn_err)) {
err += TTR("Invalid Identifier:") + " " + pn_err + "\n";
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 740a72fafa..fd61c46e63 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -80,6 +80,9 @@ extern "C" EMSCRIPTEN_KEEPALIVE void main_after_fs_sync(char *p_idbfs_err) {
Main::start();
os->get_main_loop()->init();
emscripten_resume_main_loop();
+ // Immediately run the first iteration.
+ // We are inside an animation frame, we want to immediately draw on the newly setup canvas.
+ main_loop_callback();
}
int main(int argc, char *argv[]) {
@@ -91,14 +94,15 @@ int main(int argc, char *argv[]) {
// Sync from persistent state into memory and then
// run the 'main_after_fs_sync' function.
/* clang-format off */
- EM_ASM(
+ EM_ASM({
FS.mkdir('/userfs');
FS.mount(IDBFS, {}, '/userfs');
FS.syncfs(true, function(err) {
- ccall('main_after_fs_sync', null, ['string'], [err ? err.message : ""])
+ requestAnimationFrame(function() {
+ ccall('main_after_fs_sync', null, ['string'], [err ? err.message : ""]);
+ });
});
-
- );
+ });
/* clang-format on */
return 0;
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index ef5ac66b34..a0954600a2 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -1846,37 +1846,106 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape
}
}
-DisplayServerX11::LatinKeyboardVariant DisplayServerX11::get_latin_keyboard_variant() const {
- _THREAD_SAFE_METHOD_
-
- XkbDescRec *xkbdesc = XkbAllocKeyboard();
- ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY);
+int DisplayServerX11::keyboard_get_layout_count() const {
+ int _group_count = 0;
+ XkbDescRec *kbd = XkbAllocKeyboard();
+ if (kbd) {
+ kbd->dpy = x11_display;
+ XkbGetControls(x11_display, XkbAllControlsMask, kbd);
+ XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
+
+ const Atom *groups = kbd->names->groups;
+ if (kbd->ctrls != NULL) {
+ _group_count = kbd->ctrls->num_groups;
+ } else {
+ while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
+ _group_count++;
+ }
+ }
+ XkbFreeKeyboard(kbd, 0, true);
+ }
+ return _group_count;
+}
- XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc);
- ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY);
- ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY);
+int DisplayServerX11::keyboard_get_current_layout() const {
+ XkbStateRec state;
+ XkbGetState(x11_display, XkbUseCoreKbd, &state);
+ return state.group;
+}
- char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols);
- ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY);
+void DisplayServerX11::keyboard_set_current_layout(int p_index) {
+ ERR_FAIL_INDEX(p_index, keyboard_get_layout_count());
+ XkbLockGroup(x11_display, XkbUseCoreKbd, p_index);
+}
- Vector<String> info = String(layout).split("+");
- ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY);
+String DisplayServerX11::keyboard_get_layout_language(int p_index) const {
+ String ret;
+ XkbDescRec *kbd = XkbAllocKeyboard();
+ if (kbd) {
+ kbd->dpy = x11_display;
+ XkbGetControls(x11_display, XkbAllControlsMask, kbd);
+ XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
+ XkbGetNames(x11_display, XkbGroupNamesMask, kbd);
+
+ int _group_count = 0;
+ const Atom *groups = kbd->names->groups;
+ if (kbd->ctrls != NULL) {
+ _group_count = kbd->ctrls->num_groups;
+ } else {
+ while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
+ _group_count++;
+ }
+ }
- if (info[1].find("colemak") != -1) {
- return LATIN_KEYBOARD_COLEMAK;
- } else if (info[1].find("qwertz") != -1) {
- return LATIN_KEYBOARD_QWERTZ;
- } else if (info[1].find("azerty") != -1) {
- return LATIN_KEYBOARD_AZERTY;
- } else if (info[1].find("qzerty") != -1) {
- return LATIN_KEYBOARD_QZERTY;
- } else if (info[1].find("dvorak") != -1) {
- return LATIN_KEYBOARD_DVORAK;
- } else if (info[1].find("neo") != -1) {
- return LATIN_KEYBOARD_NEO;
+ Atom names = kbd->names->symbols;
+ if (names != None) {
+ char *name = XGetAtomName(x11_display, names);
+ Vector<String> info = String(name).split("+");
+ if (p_index >= 0 && p_index < _group_count) {
+ if (p_index + 1 < info.size()) {
+ ret = info[p_index + 1]; // Skip "pc" at the start and "inet"/"group" at the end of symbols.
+ } else {
+ ret = "en"; // No symbol for layout fallback to "en".
+ }
+ } else {
+ ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ").");
+ }
+ XFree(name);
+ }
+ XkbFreeKeyboard(kbd, 0, true);
}
+ return ret.substr(0, 2);
+}
+
+String DisplayServerX11::keyboard_get_layout_name(int p_index) const {
+ String ret;
+ XkbDescRec *kbd = XkbAllocKeyboard();
+ if (kbd) {
+ kbd->dpy = x11_display;
+ XkbGetControls(x11_display, XkbAllControlsMask, kbd);
+ XkbGetNames(x11_display, XkbSymbolsNameMask, kbd);
+ XkbGetNames(x11_display, XkbGroupNamesMask, kbd);
+
+ int _group_count = 0;
+ const Atom *groups = kbd->names->groups;
+ if (kbd->ctrls != NULL) {
+ _group_count = kbd->ctrls->num_groups;
+ } else {
+ while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) {
+ _group_count++;
+ }
+ }
- return LATIN_KEYBOARD_QWERTY;
+ if (p_index >= 0 && p_index < _group_count) {
+ char *full_name = XGetAtomName(x11_display, groups[p_index]);
+ ret.parse_utf8(full_name);
+ XFree(full_name);
+ } else {
+ ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ").");
+ }
+ XkbFreeKeyboard(kbd, 0, true);
+ }
+ return ret;
}
DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) {
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index b5ea71f72a..f01b9a2323 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -327,7 +327,11 @@ public:
virtual CursorShape cursor_get_shape() const;
virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot);
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+ virtual int keyboard_get_layout_count() const;
+ virtual int keyboard_get_current_layout() const;
+ virtual void keyboard_set_current_layout(int p_index);
+ virtual String keyboard_get_layout_language(int p_index) const;
+ virtual String keyboard_get_layout_name(int p_index) const;
virtual void process_events();
diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h
index 8133dfe2c4..fddb1d0ca6 100644
--- a/platform/osx/display_server_osx.h
+++ b/platform/osx/display_server_osx.h
@@ -281,7 +281,11 @@ public:
virtual bool get_swap_ok_cancel();
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+ virtual int keyboard_get_layout_count() const;
+ virtual int keyboard_get_current_layout() const;
+ virtual void keyboard_set_current_layout(int p_index);
+ virtual String keyboard_get_layout_language(int p_index) const;
+ virtual String keyboard_get_layout_name(int p_index) const;
virtual void process_events();
virtual void force_process_and_drop_events();
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 9a1191490c..4a94e09c1c 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -2987,85 +2987,129 @@ void DisplayServerOSX::cursor_set_custom_image(const RES &p_cursor, CursorShape
}
}
+struct LayoutInfo {
+ String name;
+ String code;
+};
+
+static Vector<LayoutInfo> kbd_layouts;
+static int current_layout = 0;
static bool keyboard_layout_dirty = true;
static void keyboard_layout_changed(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef user_info) {
+ kbd_layouts.clear();
+ current_layout = 0;
keyboard_layout_dirty = true;
}
-// Returns string representation of keys, if they are printable.
-static NSString *createStringForKeys(const CGKeyCode *keyCode, int length) {
- TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
- if (!currentKeyboard)
- return nil;
+void _update_keyboard_layouts() {
+ @autoreleasepool {
+ TISInputSourceRef cur_source = TISCopyCurrentKeyboardInputSource();
+ NSString *cur_name = (NSString *)TISGetInputSourceProperty(cur_source, kTISPropertyLocalizedName);
+ CFRelease(cur_source);
- CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
- if (!layoutData)
- return nil;
+ // Enum IME layouts
+ NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode };
+ NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false);
+ for (NSUInteger i = 0; i < [list_ime count]; i++) {
+ LayoutInfo ly;
+ NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName);
+ ly.name.parse_utf8([name UTF8String]);
- const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData);
+ NSArray *langs = (NSArray *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyInputSourceLanguages);
+ ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]);
+ kbd_layouts.push_back(ly);
- OSStatus err;
- CFMutableStringRef output = CFStringCreateMutable(NULL, 0);
+ if ([name isEqualToString:cur_name]) {
+ current_layout = kbd_layouts.size() - 1;
+ }
+ }
+ [list_ime release];
- for (int i = 0; i < length; ++i) {
- UInt32 keysDown = 0;
- UniChar chars[4];
- UniCharCount realLength;
+ // Enum plain keyboard layouts
+ NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout };
+ NSArray *list_kbd = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false);
+ for (NSUInteger i = 0; i < [list_kbd count]; i++) {
+ LayoutInfo ly;
+ NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName);
+ ly.name.parse_utf8([name UTF8String]);
- err = UCKeyTranslate(keyboardLayout,
- keyCode[i],
- kUCKeyActionDisplay,
- 0,
- LMGetKbdType(),
- kUCKeyTranslateNoDeadKeysBit,
- &keysDown,
- sizeof(chars) / sizeof(chars[0]),
- &realLength,
- chars);
+ NSArray *langs = (NSArray *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyInputSourceLanguages);
+ ly.code.parse_utf8([(NSString *)[langs objectAtIndex:0] UTF8String]);
+ kbd_layouts.push_back(ly);
- if (err != noErr) {
- CFRelease(output);
- return nil;
+ if ([name isEqualToString:cur_name]) {
+ current_layout = kbd_layouts.size() - 1;
+ }
}
-
- CFStringAppendCharacters(output, chars, 1);
+ [list_kbd release];
}
- return (NSString *)output;
+ keyboard_layout_dirty = false;
}
-DisplayServerOSX::LatinKeyboardVariant DisplayServerOSX::get_latin_keyboard_variant() const {
- _THREAD_SAFE_METHOD_
-
- static LatinKeyboardVariant layout = LATIN_KEYBOARD_QWERTY;
+int DisplayServerOSX::keyboard_get_layout_count() const {
+ if (keyboard_layout_dirty) {
+ _update_keyboard_layouts();
+ }
+ return kbd_layouts.size();
+}
+void DisplayServerOSX::keyboard_set_current_layout(int p_index) {
if (keyboard_layout_dirty) {
- layout = LATIN_KEYBOARD_QWERTY;
+ _update_keyboard_layouts();
+ }
+
+ ERR_FAIL_INDEX(p_index, kbd_layouts.size());
- CGKeyCode keys[] = { kVK_ANSI_Q, kVK_ANSI_W, kVK_ANSI_E, kVK_ANSI_R, kVK_ANSI_T, kVK_ANSI_Y };
- NSString *test = createStringForKeys(keys, 6);
+ NSString *cur_name = [NSString stringWithUTF8String:kbd_layouts[p_index].name.utf8().get_data()];
- if ([test isEqualToString:@"qwertz"]) {
- layout = LATIN_KEYBOARD_QWERTZ;
- } else if ([test isEqualToString:@"azerty"]) {
- layout = LATIN_KEYBOARD_AZERTY;
- } else if ([test isEqualToString:@"qzerty"]) {
- layout = LATIN_KEYBOARD_QZERTY;
- } else if ([test isEqualToString:@"',.pyf"]) {
- layout = LATIN_KEYBOARD_DVORAK;
- } else if ([test isEqualToString:@"xvlcwk"]) {
- layout = LATIN_KEYBOARD_NEO;
- } else if ([test isEqualToString:@"qwfpgj"]) {
- layout = LATIN_KEYBOARD_COLEMAK;
+ NSDictionary *filter_kbd = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardLayout };
+ NSArray *list_kbd = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_kbd, false);
+ for (NSUInteger i = 0; i < [list_kbd count]; i++) {
+ NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_kbd objectAtIndex:i], kTISPropertyLocalizedName);
+ if ([name isEqualToString:cur_name]) {
+ TISSelectInputSource((TISInputSourceRef)[list_kbd objectAtIndex:i]);
+ break;
}
+ }
+ [list_kbd release];
- [test release];
+ NSDictionary *filter_ime = @{ (NSString *)kTISPropertyInputSourceType : (NSString *)kTISTypeKeyboardInputMode };
+ NSArray *list_ime = (NSArray *)TISCreateInputSourceList((CFDictionaryRef)filter_ime, false);
+ for (NSUInteger i = 0; i < [list_ime count]; i++) {
+ NSString *name = (NSString *)TISGetInputSourceProperty((TISInputSourceRef)[list_ime objectAtIndex:i], kTISPropertyLocalizedName);
+ if ([name isEqualToString:cur_name]) {
+ TISSelectInputSource((TISInputSourceRef)[list_ime objectAtIndex:i]);
+ break;
+ }
+ }
+ [list_ime release];
+}
+
+int DisplayServerOSX::keyboard_get_current_layout() const {
+ if (keyboard_layout_dirty) {
+ _update_keyboard_layouts();
+ }
- keyboard_layout_dirty = false;
- return layout;
+ return current_layout;
+}
+
+String DisplayServerOSX::keyboard_get_layout_language(int p_index) const {
+ if (keyboard_layout_dirty) {
+ _update_keyboard_layouts();
+ }
+
+ ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), "");
+ return kbd_layouts[p_index].code;
+}
+
+String DisplayServerOSX::keyboard_get_layout_name(int p_index) const {
+ if (keyboard_layout_dirty) {
+ _update_keyboard_layouts();
}
- return layout;
+ ERR_FAIL_INDEX_V(p_index, kbd_layouts.size(), "");
+ return kbd_layouts[p_index].name;
}
void DisplayServerOSX::_push_input(const Ref<InputEvent> &p_event) {
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 784fba75ec..8905950020 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -55,6 +55,7 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
void _fix_plist(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &plist, const String &p_binary);
void _make_icon(const Ref<Image> &p_icon, Vector<uint8_t> &p_data);
+ Error _notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path);
Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path);
Error _create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name);
void _zip_folder_recursive(zipFile &p_zip, const String &p_root_path, const String &p_folder, const String &p_pkg_name);
@@ -66,6 +67,28 @@ class EditorExportPlatformOSX : public EditorExportPlatform {
bool use_codesign() const { return false; }
bool use_dmg() const { return false; }
#endif
+ bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const {
+ String pname = p_package;
+
+ if (pname.length() == 0) {
+ if (r_error) {
+ *r_error = TTR("Identifier is missing.");
+ }
+ return false;
+ }
+
+ for (int i = 0; i < pname.length(); i++) {
+ CharType c = pname[i];
+ if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) {
+ if (r_error) {
+ *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c));
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
protected:
virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features);
@@ -122,7 +145,7 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.png,*.icns"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0"));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0"));
@@ -138,6 +161,11 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "codesign/custom_options"), PackedStringArray()));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "notarization/enable"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Apple ID email"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_id_password", PROPERTY_HINT_PLACEHOLDER_TEXT, "Enable two-factor authentication and provide app-specific password"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "notarization/apple_team_id", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide team ID if your Apple ID belongs to multiple teams"), ""));
#endif
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true));
@@ -326,8 +354,8 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
strnew += lines[i].replace("$name", p_binary) + "\n";
} else if (lines[i].find("$info") != -1) {
strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n";
- } else if (lines[i].find("$identifier") != -1) {
- strnew += lines[i].replace("$identifier", p_preset->get("application/identifier")) + "\n";
+ } else if (lines[i].find("$bundle_identifier") != -1) {
+ strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n";
} else if (lines[i].find("$short_version") != -1) {
strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n";
} else if (lines[i].find("$version") != -1) {
@@ -363,6 +391,52 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset
- and then wrap it up in a DMG
**/
+Error EditorExportPlatformOSX::_notarize(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
+#ifdef OSX_ENABLED
+ List<String> args;
+
+ args.push_back("altool");
+ args.push_back("--notarize-app");
+
+ args.push_back("--primary-bundle-id");
+ args.push_back(p_preset->get("application/bundle_identifier"));
+
+ args.push_back("--username");
+ args.push_back(p_preset->get("notarization/apple_id_name"));
+
+ args.push_back("--password");
+ args.push_back(p_preset->get("notarization/apple_id_password"));
+
+ args.push_back("--type");
+ args.push_back("osx");
+
+ if (p_preset->get("notarization/apple_team_id")) {
+ args.push_back("--asc-provider");
+ args.push_back(p_preset->get("notarization/apple_team_id"));
+ }
+
+ args.push_back("--file");
+ args.push_back(p_path);
+
+ String str;
+ Error err = OS::get_singleton()->execute("xcrun", args, true, nullptr, &str, nullptr, true);
+ ERR_FAIL_COND_V(err != OK, err);
+
+ print_line("altool (" + p_path + "):\n" + str);
+ if (str.find("RequestUUID") == -1) {
+ EditorNode::add_io_error("altool: " + str);
+ return FAILED;
+ } else {
+ print_line("Note: The notarization process generally takes less than an hour. When the process is completed, you'll receive an email.");
+ print_line(" You can check progress manually by opening a Terminal and running the following command:");
+ print_line(" \"xcrun altool --notarization-history 0 -u <your email> -p <app-specific pwd>\"");
+ }
+
+#endif
+
+ return OK;
+}
+
Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) {
#ifdef OSX_ENABLED
List<String> args;
@@ -399,7 +473,7 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese
Error err = OS::get_singleton()->execute("codesign", args, true, nullptr, &str, nullptr, true);
ERR_FAIL_COND_V(err != OK, err);
- print_line("codesign (" + p_path + "): " + str);
+ print_line("codesign (" + p_path + "):\n" + str);
if (str.find("no identity found") != -1) {
EditorNode::add_io_error("codesign: no identity found");
return FAILED;
@@ -714,6 +788,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
}
+ bool noto_enabled = p_preset->get("notarization/enable");
+ if (err == OK && noto_enabled) {
+ if (ep.step("Sending archive for notarization", 4)) {
+ return ERR_SKIP;
+ }
+ err = _notarize(p_preset, p_path);
+ }
+
// Clean up temporary .app dir.
OS::get_singleton()->move_to_trash(tmp_app_path_name);
}
@@ -803,6 +885,41 @@ bool EditorExportPlatformOSX::can_export(const Ref<EditorExportPreset> &p_preset
valid = dvalid || rvalid;
r_missing_templates = !valid;
+ String identifier = p_preset->get("application/bundle_identifier");
+ String pn_err;
+ if (!is_package_name_valid(identifier, &pn_err)) {
+ err += TTR("Invalid bundle identifier:") + " " + pn_err + "\n";
+ valid = false;
+ }
+
+ bool sign_enabled = p_preset->get("codesign/enable");
+ if (sign_enabled) {
+ if (p_preset->get("codesign/identity") == "") {
+ err += TTR("Codesign: identity not specified.") + "\n";
+ valid = false;
+ }
+ }
+ bool noto_enabled = p_preset->get("notarization/enable");
+ if (noto_enabled) {
+ if (!sign_enabled) {
+ err += TTR("Notarization: code signing required.") + "\n";
+ valid = false;
+ }
+ bool hr_enabled = p_preset->get("codesign/hardened_runtime");
+ if (!hr_enabled) {
+ err += TTR("Notarization: hardened runtime required.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_name") == "") {
+ err += TTR("Notarization: Apple ID name not specified.") + "\n";
+ valid = false;
+ }
+ if (p_preset->get("notarization/apple_id_password") == "") {
+ err += TTR("Notarization: Apple ID password not specified.") + "\n";
+ valid = false;
+ }
+ }
+
if (!err.empty()) {
r_error = err;
}
diff --git a/platform/uwp/export/export.cpp b/platform/uwp/export/export.cpp
index db42908f89..0fd017f96e 100644
--- a/platform/uwp/export/export.cpp
+++ b/platform/uwp/export/export.cpp
@@ -743,23 +743,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
// TODO: Add resource creation or image rescaling to enable other scales:
// 1.25, 1.5, 2.0
- real_t scales[] = { 1.0 };
- bool valid_w = false;
- bool valid_h = false;
-
- for (int i = 0; i < 1; i++) {
- int w = ceil(p_width * scales[i]);
- int h = ceil(p_height * scales[i]);
-
- if (w == p_image->get_width()) {
- valid_w = true;
- }
- if (h == p_image->get_height()) {
- valid_h = true;
- }
- }
-
- return valid_w && valid_h;
+ return p_width == p_image->get_width() && p_height == p_image->get_height();
}
Vector<uint8_t> _fix_manifest(const Ref<EditorExportPreset> &p_preset, const Vector<uint8_t> &p_template, bool p_give_internet) const {
@@ -986,7 +970,7 @@ class EditorExportPlatformUWP : public EditorExportPlatform {
public:
virtual String get_name() const {
- return "Windows Universal";
+ return "UWP";
}
virtual String get_os_name() const {
return "UWP";
@@ -1196,7 +1180,7 @@ public:
virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) {
String src_appx;
- EditorProgress ep("export", "Exporting for Windows Universal", 7, true);
+ EditorProgress ep("export", "Exporting for UWP", 7, true);
if (p_debug) {
src_appx = p_preset->get("custom_template/debug");
diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp
index 7bd67d3726..ee25754704 100644
--- a/platform/uwp/os_uwp.cpp
+++ b/platform/uwp/os_uwp.cpp
@@ -535,11 +535,28 @@ void OS_UWP::delay_usec(uint32_t p_usec) const {
uint64_t OS_UWP::get_ticks_usec() const {
uint64_t ticks;
- uint64_t time;
+
// This is the number of clock ticks since start
QueryPerformanceCounter((LARGE_INTEGER *)&ticks);
+
// Divide by frequency to get the time in seconds
- time = ticks * 1000000L / ticks_per_second;
+ // original calculation shown below is subject to overflow
+ // with high ticks_per_second and a number of days since the last reboot.
+ // time = ticks * 1000000L / ticks_per_second;
+
+ // we can prevent this by either using 128 bit math
+ // or separating into a calculation for seconds, and the fraction
+ uint64_t seconds = ticks / ticks_per_second;
+
+ // compiler will optimize these two into one divide
+ uint64_t leftover = ticks % ticks_per_second;
+
+ // remainder
+ uint64_t time = (leftover * 1000000L) / ticks_per_second;
+
+ // seconds
+ time += seconds * 1000000L;
+
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index a1a604d0cb..7cb6e90edb 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -1372,70 +1372,99 @@ void DisplayServerWindows::enable_for_stealing_focus(OS::ProcessID pid) {
AllowSetForegroundWindow(pid);
}
-DisplayServer::LatinKeyboardVariant DisplayServerWindows::get_latin_keyboard_variant() const {
- _THREAD_SAFE_METHOD_
+int DisplayServerWindows::keyboard_get_layout_count() const {
+ return GetKeyboardLayoutList(0, NULL);
+}
- unsigned long azerty[] = {
- 0x00020401, // Arabic (102) AZERTY
- 0x0001080c, // Belgian (Comma)
- 0x0000080c, // Belgian French
- 0x0000040c, // French
- 0 // <--- STOP MARK
- };
- unsigned long qwertz[] = {
- 0x0000041a, // Croation
- 0x00000405, // Czech
- 0x00000407, // German
- 0x00010407, // German (IBM)
- 0x0000040e, // Hungarian
- 0x0000046e, // Luxembourgish
- 0x00010415, // Polish (214)
- 0x00000418, // Romanian (Legacy)
- 0x0000081a, // Serbian (Latin)
- 0x0000041b, // Slovak
- 0x00000424, // Slovenian
- 0x0001042e, // Sorbian Extended
- 0x0002042e, // Sorbian Standard
- 0x0000042e, // Sorbian Standard (Legacy)
- 0x0000100c, // Swiss French
- 0x00000807, // Swiss German
- 0 // <--- STOP MARK
- };
- unsigned long dvorak[] = {
- 0x00010409, // US-Dvorak
- 0x00030409, // US-Dvorak for left hand
- 0x00040409, // US-Dvorak for right hand
- 0 // <--- STOP MARK
- };
+int DisplayServerWindows::keyboard_get_current_layout() const {
+ HKL cur_layout = GetKeyboardLayout(0);
+
+ int layout_count = GetKeyboardLayoutList(0, NULL);
+ HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
+ GetKeyboardLayoutList(layout_count, layouts);
+
+ for (int i = 0; i < layout_count; i++) {
+ if (cur_layout == layouts[i]) {
+ memfree(layouts);
+ return i;
+ }
+ }
+ memfree(layouts);
+ return -1;
+}
+
+void DisplayServerWindows::keyboard_set_current_layout(int p_index) {
+ int layout_count = GetKeyboardLayoutList(0, NULL);
+
+ ERR_FAIL_INDEX(p_index, layout_count);
+
+ HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
+ GetKeyboardLayoutList(layout_count, layouts);
+ ActivateKeyboardLayout(layouts[p_index], KLF_SETFORPROCESS);
+ memfree(layouts);
+}
+
+String DisplayServerWindows::keyboard_get_layout_language(int p_index) const {
+ int layout_count = GetKeyboardLayoutList(0, NULL);
- char name[KL_NAMELENGTH + 1];
- name[0] = 0;
- GetKeyboardLayoutNameA(name);
+ ERR_FAIL_INDEX_V(p_index, layout_count, "");
- unsigned long hex = strtoul(name, nullptr, 16);
+ HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
+ GetKeyboardLayoutList(layout_count, layouts);
- int i = 0;
- while (azerty[i] != 0) {
- if (azerty[i] == hex)
- return LATIN_KEYBOARD_AZERTY;
- i++;
+ wchar_t buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
+
+ memfree(layouts);
+
+ return String(buf).substr(0, 2);
+}
+
+String _get_full_layout_name_from_registry(HKL p_layout) {
+ String id = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layouts\\" + String::num_int64((int64_t)p_layout, 16, false).lpad(8, "0");
+ String ret;
+
+ HKEY hkey;
+ wchar_t layout_text[1024];
+ memset(layout_text, 0, 1024 * sizeof(wchar_t));
+
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, (LPCWSTR)id.c_str(), 0, KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS) {
+ return ret;
}
- i = 0;
- while (qwertz[i] != 0) {
- if (qwertz[i] == hex)
- return LATIN_KEYBOARD_QWERTZ;
- i++;
+ DWORD buffer = 1024;
+ DWORD vtype = REG_SZ;
+ if (RegQueryValueExW(hkey, L"Layout Text", NULL, &vtype, (LPBYTE)layout_text, &buffer) == ERROR_SUCCESS) {
+ ret = String(layout_text);
}
+ RegCloseKey(hkey);
+ return ret;
+}
+
+String DisplayServerWindows::keyboard_get_layout_name(int p_index) const {
+ int layout_count = GetKeyboardLayoutList(0, NULL);
+
+ ERR_FAIL_INDEX_V(p_index, layout_count, "");
+
+ HKL *layouts = (HKL *)memalloc(layout_count * sizeof(HKL));
+ GetKeyboardLayoutList(layout_count, layouts);
- i = 0;
- while (dvorak[i] != 0) {
- if (dvorak[i] == hex)
- return LATIN_KEYBOARD_DVORAK;
- i++;
+ String ret = _get_full_layout_name_from_registry(layouts[p_index]); // Try reading full name from Windows registry, fallback to locale name if failed (e.g. on Wine).
+ if (ret == String()) {
+ wchar_t buf[LOCALE_NAME_MAX_LENGTH];
+ memset(buf, 0, LOCALE_NAME_MAX_LENGTH * sizeof(wchar_t));
+ LCIDToLocaleName(MAKELCID(LOWORD(layouts[p_index]), SORT_DEFAULT), buf, LOCALE_NAME_MAX_LENGTH, 0);
+
+ wchar_t name[1024];
+ memset(name, 0, 1024 * sizeof(wchar_t));
+ GetLocaleInfoEx(buf, LOCALE_SLOCALIZEDDISPLAYNAME, (LPWSTR)&name, 1024);
+
+ ret = String(name);
}
+ memfree(layouts);
- return LATIN_KEYBOARD_QWERTY;
+ return ret;
}
void DisplayServerWindows::process_events() {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index caf8598dc2..995ced0809 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -523,7 +523,11 @@ public:
virtual void enable_for_stealing_focus(OS::ProcessID pid);
- virtual LatinKeyboardVariant get_latin_keyboard_variant() const;
+ virtual int keyboard_get_layout_count() const;
+ virtual int keyboard_get_current_layout() const;
+ virtual void keyboard_set_current_layout(int p_index);
+ virtual String keyboard_get_layout_language(int p_index) const;
+ virtual String keyboard_get_layout_name(int p_index) const;
virtual void process_events();
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 0dab0c601a..5b15896b0c 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -208,6 +208,13 @@ void OS_Windows::initialize() {
process_map = memnew((Map<ProcessID, ProcessInfo>));
+ // Add current Godot PID to the list of known PIDs
+ ProcessInfo current_pi = {};
+ PROCESS_INFORMATION current_pi_pi = {};
+ current_pi.pi = current_pi_pi;
+ current_pi.pi.hProcess = GetCurrentProcess();
+ process_map->insert(GetCurrentProcessId(), current_pi);
+
IP_Unix::make_default();
main_loop = nullptr;
}
@@ -343,55 +350,21 @@ OS::TimeZoneInfo OS_Windows::get_time_zone_info() const {
return ret;
}
-uint64_t OS_Windows::get_unix_time() const {
- FILETIME ft;
- SYSTEMTIME st;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &ft);
-
- SYSTEMTIME ep;
- ep.wYear = 1970;
- ep.wMonth = 1;
- ep.wDayOfWeek = 4;
- ep.wDay = 1;
- ep.wHour = 0;
- ep.wMinute = 0;
- ep.wSecond = 0;
- ep.wMilliseconds = 0;
- FILETIME fep;
- SystemTimeToFileTime(&ep, &fep);
-
- // Type punning through unions (rather than pointer cast) as per:
- // https://docs.microsoft.com/en-us/windows/desktop/api/minwinbase/ns-minwinbase-filetime#remarks
- ULARGE_INTEGER ft_punning;
- ft_punning.LowPart = ft.dwLowDateTime;
- ft_punning.HighPart = ft.dwHighDateTime;
-
- ULARGE_INTEGER fep_punning;
- fep_punning.LowPart = fep.dwLowDateTime;
- fep_punning.HighPart = fep.dwHighDateTime;
-
- return (ft_punning.QuadPart - fep_punning.QuadPart) / 10000000;
-};
-
-uint64_t OS_Windows::get_system_time_secs() const {
- return get_system_time_msecs() / 1000;
-}
-
-uint64_t OS_Windows::get_system_time_msecs() const {
- const uint64_t WINDOWS_TICK = 10000;
- const uint64_t MSEC_TO_UNIX_EPOCH = 11644473600000LL;
+double OS_Windows::get_unix_time() const {
+ // 1 Windows tick is 100ns
+ const uint64_t WINDOWS_TICKS_PER_SECOND = 10000000;
+ const uint64_t TICKS_TO_UNIX_EPOCH = 116444736000000000LL;
SYSTEMTIME st;
GetSystemTime(&st);
FILETIME ft;
SystemTimeToFileTime(&st, &ft);
- uint64_t ret;
- ret = ft.dwHighDateTime;
- ret <<= 32;
- ret |= ft.dwLowDateTime;
+ uint64_t ticks_time;
+ ticks_time = ft.dwHighDateTime;
+ ticks_time <<= 32;
+ ticks_time |= ft.dwLowDateTime;
- return (uint64_t)(ret / WINDOWS_TICK - MSEC_TO_UNIX_EPOCH);
+ return (double)(ticks_time - TICKS_TO_UNIX_EPOCH) / WINDOWS_TICKS_PER_SECOND;
}
void OS_Windows::delay_usec(uint32_t p_usec) const {
@@ -403,12 +376,29 @@ void OS_Windows::delay_usec(uint32_t p_usec) const {
uint64_t OS_Windows::get_ticks_usec() const {
uint64_t ticks;
- uint64_t time;
+
// This is the number of clock ticks since start
if (!QueryPerformanceCounter((LARGE_INTEGER *)&ticks))
ticks = (UINT64)timeGetTime();
+
// Divide by frequency to get the time in seconds
- time = ticks * 1000000L / ticks_per_second;
+ // original calculation shown below is subject to overflow
+ // with high ticks_per_second and a number of days since the last reboot.
+ // time = ticks * 1000000L / ticks_per_second;
+
+ // we can prevent this by either using 128 bit math
+ // or separating into a calculation for seconds, and the fraction
+ uint64_t seconds = ticks / ticks_per_second;
+
+ // compiler will optimize these two into one divide
+ uint64_t leftover = ticks % ticks_per_second;
+
+ // remainder
+ uint64_t time = (leftover * 1000000L) / ticks_per_second;
+
+ // seconds
+ time += seconds * 1000000L;
+
// Subtract the time at game start to get
// the time since the game started
time -= ticks_start;
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 11e3533bfd..910a83539a 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -129,9 +129,7 @@ public:
virtual Date get_date(bool utc) const;
virtual Time get_time(bool utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
- virtual uint64_t get_unix_time() const;
- virtual uint64_t get_system_time_secs() const;
- virtual uint64_t get_system_time_msecs() const;
+ virtual double get_unix_time() const;
virtual Error set_cwd(const String &p_cwd);