summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/detect.py2
-rw-r--r--platform/android/display_server_android.cpp21
-rw-r--r--platform/javascript/detect.py2
-rw-r--r--platform/javascript/display_server_javascript.cpp4
-rw-r--r--platform/javascript/js/libs/library_godot_os.js2
-rw-r--r--platform/linuxbsd/detect.py19
-rw-r--r--platform/linuxbsd/display_server_x11.cpp350
-rw-r--r--platform/linuxbsd/display_server_x11.h8
-rw-r--r--platform/osx/display_server_osx.mm38
-rw-r--r--platform/osx/export/export.cpp35
-rw-r--r--platform/server/detect.py31
-rw-r--r--platform/windows/display_server_windows.cpp40
12 files changed, 443 insertions, 109 deletions
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 0accacb679..60d4146712 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -215,7 +215,7 @@ def configure(env):
env.Append(CPPFLAGS=["-isystem", env["ANDROID_NDK_ROOT"] + "/sources/cxx-stl/llvm-libc++abi/include"])
# Disable exceptions and rtti on non-tools (template) builds
- if env["tools"]:
+ if env["tools"] or env["builtin_icu"]:
env.Append(CXXFLAGS=["-frtti"])
else:
env.Append(CXXFLAGS=["-fno-rtti", "-fno-exceptions"])
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index e82a12ece5..aab5da4fde 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -498,9 +498,28 @@ void DisplayServerAndroid::_set_key_modifier_state(Ref<InputEventWithModifiers>
}
void DisplayServerAndroid::process_key_event(int p_keycode, int p_scancode, int p_unicode_char, bool p_pressed) {
+ static char32_t prev_wc = 0;
+ char32_t unicode = p_unicode_char;
+ if ((p_unicode_char & 0xfffffc00) == 0xd800) {
+ if (prev_wc != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wc = unicode;
+ return; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wc == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ return; // Skip invalid surrogate.
+ }
+ unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wc = 0;
+ } else {
+ prev_wc = 0;
+ }
+
Ref<InputEventKey> ev;
ev.instance();
- int val = p_unicode_char;
+ int val = unicode;
int keycode = android_get_keysym(p_keycode);
int phy_keycode = android_get_keysym(p_scancode);
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 71189cf697..9f584d0899 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -71,6 +71,8 @@ def configure(env):
)
# Tools need more memory. Initial stack memory in bytes. See `src/settings.js` in emscripten repository (will be renamed to INITIAL_MEMORY).
env.Append(LINKFLAGS=["-s", "TOTAL_MEMORY=33554432"])
+ elif env["builtin_icu"]:
+ env.Append(CCFLAGS=["-frtti"])
else:
# Disable exceptions and rtti on non-tools (template) builds
# These flags help keep the file size down.
diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp
index af8800d565..92e13553fc 100644
--- a/platform/javascript/display_server_javascript.cpp
+++ b/platform/javascript/display_server_javascript.cpp
@@ -948,8 +948,8 @@ void DisplayServerJavaScript::window_set_size(const Size2i p_size, WindowID p_wi
last_width = p_size.x;
last_height = p_size.y;
double scale = godot_js_display_pixel_ratio_get();
- emscripten_set_canvas_element_size(canvas_id, p_size.x * scale, p_size.y * scale);
- emscripten_set_element_css_size(canvas_id, p_size.x, p_size.y);
+ emscripten_set_canvas_element_size(canvas_id, p_size.x, p_size.y);
+ emscripten_set_element_css_size(canvas_id, p_size.x / scale, p_size.y / scale);
}
Size2i DisplayServerJavaScript::window_get_size(WindowID p_window) const {
diff --git a/platform/javascript/js/libs/library_godot_os.js b/platform/javascript/js/libs/library_godot_os.js
index 488753d704..44b104922e 100644
--- a/platform/javascript/js/libs/library_godot_os.js
+++ b/platform/javascript/js/libs/library_godot_os.js
@@ -200,7 +200,7 @@ const GodotFS = {
}
FS.mkdirTree(dir);
}
- FS.writeFile(path, new Uint8Array(buffer), { 'flags': 'wx+' });
+ FS.writeFile(path, new Uint8Array(buffer));
},
},
};
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index a8bc3a09f6..277aafc107 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -205,14 +205,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ if (
+ env["builtin_freetype"]
+ or env["builtin_libpng"]
+ or env["builtin_zlib"]
+ or env["builtin_graphite"]
+ or env["builtin_harfbuzz"]
+ ):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
+ env["builtin_graphite"] = True
+ env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
+ if not env["builtin_graphite"]:
+ env.ParseConfig("pkg-config graphite2 --cflags --libs")
+
+ if not env["builtin_icu"]:
+ env.ParseConfig("pkg-config icu-uc --cflags --libs")
+
+ if not env["builtin_harfbuzz"]:
+ env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
+
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index 5fa737af8e..c7559e4a40 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -43,6 +43,7 @@
#include "servers/rendering/rasterizer_rd/rasterizer_rd.h"
#endif
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -465,59 +466,138 @@ Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *
}
}
+Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) {
+ if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) {
+ return True;
+ } else {
+ return False;
+ }
+}
+
String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const {
String ret;
- Atom type;
- Atom selection = XA_PRIMARY;
- int format, result;
- unsigned long len, bytes_left, dummy;
- unsigned char *data;
Window selection_owner = XGetSelectionOwner(x11_display, p_source);
-
if (selection_owner == x11_window) {
return internal_clipboard;
}
if (selection_owner != None) {
- {
- // Block events polling while processing selection events.
- MutexLock mutex_lock(events_mutex);
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
- XConvertSelection(x11_display, p_source, target, selection,
- x11_window, CurrentTime);
+ Atom selection = XA_PRIMARY;
+ XConvertSelection(x11_display, p_source, target, selection,
+ x11_window, CurrentTime);
- XFlush(x11_display);
+ XFlush(x11_display);
- // Blocking wait for predicate to be True
- // and remove the event from the queue.
- XEvent event;
- XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- }
+ // Blocking wait for predicate to be True and remove the event from the queue.
+ XEvent event;
+ XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
- //
- // Do not get any data, see how much data is there
- //
+ // Do not get any data, see how much data is there.
+ Atom type;
+ int format, result;
+ unsigned long len, bytes_left, dummy;
+ unsigned char *data;
XGetWindowProperty(x11_display, x11_window,
selection, // Tricky..
0, 0, // offset - len
0, // Delete 0==FALSE
- AnyPropertyType, //flag
+ AnyPropertyType, // flag
&type, // return type
&format, // return format
- &len, &bytes_left, //that
+ &len, &bytes_left, // data length
&data);
- // DATA is There
- if (bytes_left > 0) {
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (type == XInternAtom(x11_display, "INCR", 0)) {
+ // Data is going to be received incrementally.
+ DEBUG_LOG_X11("INCR selection started.\n");
+
+ LocalVector<uint8_t> incr_data;
+ uint32_t data_size = 0;
+ bool success = false;
+
+ // Delete INCR property to notify the owner.
+ XDeleteProperty(x11_display, x11_window, type);
+
+ // Process events from the queue.
+ bool done = false;
+ while (!done) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) {
+ result = XGetWindowProperty(x11_display, x11_window,
+ selection, // selection type
+ 0, LONG_MAX, // offset - len
+ True, // delete property to notify the owner
+ AnyPropertyType, // flag
+ &type, // return type
+ &format, // return format
+ &len, &bytes_left, // data length
+ &data);
+
+ DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format);
+
+ if (result == Success) {
+ if (data && (len > 0)) {
+ uint32_t prev_size = incr_data.size();
+ if (prev_size == 0) {
+ // First property contains initial data size.
+ unsigned long initial_size = *(unsigned long *)data;
+ incr_data.resize(initial_size);
+ } else {
+ // New chunk, resize to be safe and append data.
+ incr_data.resize(MAX(data_size + len, prev_size));
+ memcpy(incr_data.ptr() + data_size, data, len);
+ data_size += len;
+ }
+ } else {
+ // Last chunk, process finished.
+ done = true;
+ success = true;
+ }
+ } else {
+ printf("Failed to get selection data chunk.\n");
+ done = true;
+ }
+
+ if (data) {
+ XFree(data);
+ }
+
+ if (done) {
+ break;
+ }
+ }
+ }
+
+ if (success && (data_size > 0)) {
+ ret.parse_utf8((const char *)incr_data.ptr(), data_size);
+ }
+ } else if (bytes_left > 0) {
+ // Data is ready and can be processed all at once.
result = XGetWindowProperty(x11_display, x11_window,
selection, 0, bytes_left, 0,
AnyPropertyType, &type, &format,
&len, &dummy, &data);
+
if (result == Success) {
ret.parse_utf8((const char *)data);
} else {
- printf("FAIL\n");
+ printf("Failed to get selection data.\n");
}
+
if (data) {
XFree(data);
}
@@ -552,6 +632,60 @@ String DisplayServerX11::clipboard_get() const {
return ret;
}
+Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) {
+ if (event->xany.window == *(Window *)arg) {
+ return (event->type == SelectionRequest) ||
+ (event->type == SelectionNotify);
+ } else {
+ return False;
+ }
+}
+
+void DisplayServerX11::_clipboard_transfer_ownership(Atom p_source, Window x11_window) const {
+ _THREAD_SAFE_METHOD_
+
+ Window selection_owner = XGetSelectionOwner(x11_display, p_source);
+
+ if (selection_owner != x11_window) {
+ return;
+ }
+
+ // Block events polling while processing selection events.
+ MutexLock mutex_lock(events_mutex);
+
+ Atom clipboard_manager = XInternAtom(x11_display, "CLIPBOARD_MANAGER", False);
+ Atom save_targets = XInternAtom(x11_display, "SAVE_TARGETS", False);
+ XConvertSelection(x11_display, clipboard_manager, save_targets, None,
+ x11_window, CurrentTime);
+
+ // Process events from the queue.
+ while (true) {
+ if (!_wait_for_events()) {
+ // Error or timeout, abort.
+ break;
+ }
+
+ // Non-blocking wait for next event and remove it from the queue.
+ XEvent ev;
+ while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_save_targets, (XPointer)&x11_window)) {
+ switch (ev.type) {
+ case SelectionRequest:
+ _handle_selection_request_event(&(ev.xselectionrequest));
+ break;
+
+ case SelectionNotify: {
+ if (ev.xselection.target == save_targets) {
+ // Once SelectionNotify is received, we're done whether it succeeded or not.
+ return;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+}
+
int DisplayServerX11::get_screen_count() const {
_THREAD_SAFE_METHOD_
@@ -2291,53 +2425,105 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event,
Input::get_singleton()->accumulate_input_event(k);
}
-void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) {
- XEvent respond;
- if (p_event->target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
- p_event->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
- p_event->target == XInternAtom(x11_display, "TEXT", 0) ||
- p_event->target == XA_STRING ||
- p_event->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
- p_event->target == XInternAtom(x11_display, "text/plain", 0)) {
- // Directly using internal clipboard because we know our window
- // is the owner during a selection request.
- CharString clip = internal_clipboard.utf8();
- XChangeProperty(x11_display,
- p_event->requestor,
- p_event->property,
- p_event->target,
- 8,
- PropModeReplace,
- (unsigned char *)clip.get_data(),
- clip.length());
- respond.xselection.property = p_event->property;
- } else if (p_event->target == XInternAtom(x11_display, "TARGETS", 0)) {
- Atom data[7];
+Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const {
+ if (p_target == XInternAtom(x11_display, "TARGETS", 0)) {
+ // Request to list all supported targets.
+ Atom data[9];
data[0] = XInternAtom(x11_display, "TARGETS", 0);
- data[1] = XInternAtom(x11_display, "UTF8_STRING", 0);
- data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
- data[3] = XInternAtom(x11_display, "TEXT", 0);
- data[4] = XA_STRING;
- data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
- data[6] = XInternAtom(x11_display, "text/plain", 0);
+ data[1] = XInternAtom(x11_display, "SAVE_TARGETS", 0);
+ data[2] = XInternAtom(x11_display, "MULTIPLE", 0);
+ data[3] = XInternAtom(x11_display, "UTF8_STRING", 0);
+ data[4] = XInternAtom(x11_display, "COMPOUND_TEXT", 0);
+ data[5] = XInternAtom(x11_display, "TEXT", 0);
+ data[6] = XA_STRING;
+ data[7] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0);
+ data[8] = XInternAtom(x11_display, "text/plain", 0);
XChangeProperty(x11_display,
- p_event->requestor,
- p_event->property,
+ p_requestor,
+ p_property,
XA_ATOM,
32,
PropModeReplace,
(unsigned char *)&data,
sizeof(data) / sizeof(data[0]));
- respond.xselection.property = p_event->property;
-
+ return p_property;
+ } else if (p_target == XInternAtom(x11_display, "SAVE_TARGETS", 0)) {
+ // Request to check if SAVE_TARGETS is supported, nothing special to do.
+ XChangeProperty(x11_display,
+ p_requestor,
+ p_property,
+ XInternAtom(x11_display, "NULL", False),
+ 32,
+ PropModeReplace,
+ nullptr,
+ 0);
+ return p_property;
+ } else if (p_target == XInternAtom(x11_display, "UTF8_STRING", 0) ||
+ p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) ||
+ p_target == XInternAtom(x11_display, "TEXT", 0) ||
+ p_target == XA_STRING ||
+ p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) ||
+ p_target == XInternAtom(x11_display, "text/plain", 0)) {
+ // Directly using internal clipboard because we know our window
+ // is the owner during a selection request.
+ CharString clip = internal_clipboard.utf8();
+ XChangeProperty(x11_display,
+ p_requestor,
+ p_property,
+ p_target,
+ 8,
+ PropModeReplace,
+ (unsigned char *)clip.get_data(),
+ clip.length());
+ return p_property;
} else {
- char *targetname = XGetAtomName(x11_display, p_event->target);
- printf("No Target '%s'\n", targetname);
- if (targetname) {
- XFree(targetname);
+ char *target_name = XGetAtomName(x11_display, p_target);
+ printf("Target '%s' not supported.\n", target_name);
+ if (target_name) {
+ XFree(target_name);
}
+ return None;
+ }
+}
+
+void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) const {
+ XEvent respond;
+ if (p_event->target == XInternAtom(x11_display, "MULTIPLE", 0)) {
+ // Request for multiple target conversions at once.
+ Atom atom_pair = XInternAtom(x11_display, "ATOM_PAIR", False);
respond.xselection.property = None;
+
+ Atom type;
+ int format;
+ unsigned long len;
+ unsigned long remaining;
+ unsigned char *data = nullptr;
+ if (XGetWindowProperty(x11_display, p_event->requestor, p_event->property, 0, LONG_MAX, False, atom_pair, &type, &format, &len, &remaining, &data) == Success) {
+ if ((len >= 2) && data) {
+ Atom *targets = (Atom *)data;
+ for (uint64_t i = 0; i < len; i += 2) {
+ Atom target = targets[i];
+ Atom &property = targets[i + 1];
+ property = _process_selection_request_target(target, p_event->requestor, property);
+ }
+
+ XChangeProperty(x11_display,
+ p_event->requestor,
+ p_event->property,
+ atom_pair,
+ 32,
+ PropModeReplace,
+ (unsigned char *)targets,
+ len);
+
+ respond.xselection.property = p_event->property;
+ }
+ XFree(data);
+ }
+ } else {
+ // Request for target conversion.
+ respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property);
}
respond.xselection.type = SelectionNotify;
@@ -2473,32 +2659,43 @@ Bool DisplayServerX11::_predicate_all_events(Display *display, XEvent *event, XP
return True;
}
-void DisplayServerX11::_poll_events() {
+bool DisplayServerX11::_wait_for_events() const {
int x11_fd = ConnectionNumber(x11_display);
fd_set in_fds;
- while (!events_thread_done) {
- XFlush(x11_display);
+ XFlush(x11_display);
- FD_ZERO(&in_fds);
- FD_SET(x11_fd, &in_fds);
+ FD_ZERO(&in_fds);
+ FD_SET(x11_fd, &in_fds);
- struct timeval tv;
- tv.tv_usec = 0;
- tv.tv_sec = 1;
+ struct timeval tv;
+ tv.tv_usec = 0;
+ tv.tv_sec = 1;
- // Wait for next event or timeout.
- int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+ // Wait for next event or timeout.
+ int num_ready_fds = select(x11_fd + 1, &in_fds, NULL, NULL, &tv);
+
+ if (num_ready_fds > 0) {
+ // Event received.
+ return true;
+ } else {
+ // Error or timeout.
if (num_ready_fds < 0) {
- ERR_PRINT("_poll_events: select error: " + itos(errno));
+ ERR_PRINT("_wait_for_events: select error: " + itos(errno));
}
+ return false;
+ }
+}
+
+void DisplayServerX11::_poll_events() {
+ while (!events_thread_done) {
+ _wait_for_events();
// Process events from the queue.
{
MutexLock mutex_lock(events_mutex);
- // Non-blocking wait for next event
- // and remove it from the queue.
+ // Non-blocking wait for next event and remove it from the queue.
XEvent ev;
while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) {
// Check if the input manager wants to process the event.
@@ -4068,6 +4265,11 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
}
DisplayServerX11::~DisplayServerX11() {
+ // Send owned clipboard data to clipboard manager before exit.
+ Window x11_main_window = windows[MAIN_WINDOW_ID].x11_window;
+ _clipboard_transfer_ownership(XA_PRIMARY, x11_main_window);
+ _clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window);
+
events_thread_done = true;
Thread::wait_to_finish(events_thread);
memdelete(events_thread);
diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h
index 9ff28b9ed2..61fb04cbf3 100644
--- a/platform/linuxbsd/display_server_x11.h
+++ b/platform/linuxbsd/display_server_x11.h
@@ -204,10 +204,13 @@ class DisplayServerX11 : public DisplayServer {
Point2i center;
void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false);
- void _handle_selection_request_event(XSelectionRequestEvent *p_event);
+
+ Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const;
+ void _handle_selection_request_event(XSelectionRequestEvent *p_event) const;
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
String _clipboard_get(Atom p_source, Window x11_window) const;
+ void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const;
//bool minimized;
//bool window_has_focus;
@@ -262,10 +265,13 @@ class DisplayServerX11 : public DisplayServer {
bool events_thread_done = false;
LocalVector<XEvent> polled_events;
static void _poll_events_thread(void *ud);
+ bool _wait_for_events() const;
void _poll_events();
static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg);
static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg);
+ static Bool _predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg);
protected:
void _window_changed(XEvent *event);
diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm
index 1ad7117b39..3025210195 100644
--- a/platform/osx/display_server_osx.mm
+++ b/platform/osx/display_server_osx.mm
@@ -701,8 +701,6 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
characters = (NSString *)aString;
}
- NSUInteger i, length = [characters length];
-
NSCharacterSet *ctrlChars = [NSCharacterSet controlCharacterSet];
NSCharacterSet *wsnlChars = [NSCharacterSet whitespaceAndNewlineCharacterSet];
if ([characters rangeOfCharacterFromSet:ctrlChars].length && [characters rangeOfCharacterFromSet:wsnlChars].length == 0) {
@@ -712,8 +710,15 @@ static const NSRange kEmptyRange = { NSNotFound, 0 };
return;
}
- for (i = 0; i < length; i++) {
- const unichar codepoint = [characters characterAtIndex:i];
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
if ((codepoint & 0xFF00) == 0xF700) {
continue;
}
@@ -1315,7 +1320,16 @@ static int remapKey(unsigned int key, unsigned int state) {
if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
// Fallback unicode character handler used if IME is not active
- for (NSUInteger i = 0; i < length; i++) {
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
+
DisplayServerOSX::KeyEvent ke;
ke.window_id = window_id;
@@ -1325,7 +1339,7 @@ static int remapKey(unsigned int key, unsigned int state) {
ke.keycode = remapKey([event keyCode], [event modifierFlags]);
ke.physical_keycode = translateKey([event keyCode]);
ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
+ ke.unicode = codepoint;
_push_to_key_event_buffer(ke);
}
@@ -1417,7 +1431,15 @@ static int remapKey(unsigned int key, unsigned int state) {
// Fallback unicode character handler used if IME is not active
if (!wd.im_active && length > 0 && keycode_has_unicode(remapKey([event keyCode], [event modifierFlags]))) {
- for (NSUInteger i = 0; i < length; i++) {
+ Char16String text;
+ text.resize([characters length] + 1);
+ [characters getCharacters:(unichar *)text.ptrw() range:NSMakeRange(0, [characters length])];
+
+ String u32text;
+ u32text.parse_utf16(text.ptr(), text.length());
+
+ for (int i = 0; i < u32text.length(); i++) {
+ const char32_t codepoint = u32text[i];
DisplayServerOSX::KeyEvent ke;
ke.window_id = window_id;
@@ -1427,7 +1449,7 @@ static int remapKey(unsigned int key, unsigned int state) {
ke.keycode = remapKey([event keyCode], [event modifierFlags]);
ke.physical_keycode = translateKey([event keyCode]);
ke.raw = true;
- ke.unicode = [characters characterAtIndex:i];
+ ke.unicode = codepoint;
_push_to_key_event_buffer(ke);
}
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index e988e51e72..1dfe614b49 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -42,7 +42,7 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "platform/osx/logo.gen.h"
-#include "string.h"
+
#include <sys/stat.h>
class EditorExportPlatformOSX : public EditorExportPlatform {
@@ -572,36 +572,36 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
pkg_name = "Unnamed";
}
- String pkg_name_safe = OS::get_singleton()->get_safe_dir_name(pkg_name);
-
- Error err = OK;
- String tmp_app_path_name = "";
+ pkg_name = OS::get_singleton()->get_safe_dir_name(pkg_name);
- DirAccess *tmp_app_path = nullptr;
String export_format = use_dmg() && p_path.ends_with("dmg") ? "dmg" : "zip";
// Create our application bundle.
- tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".app");
+ String tmp_app_dir_name = pkg_name;
+ String tmp_app_path_name = EditorSettings::get_singleton()->get_cache_dir().plus_file(tmp_app_dir_name);
print_line("Exporting to " + tmp_app_path_name);
- tmp_app_path = DirAccess::create_for_path(tmp_app_path_name);
- if (!tmp_app_path) {
+
+ Error err = OK;
+
+ DirAccessRef tmp_app_dir = DirAccess::create_for_path(tmp_app_path_name);
+ if (!tmp_app_dir) {
err = ERR_CANT_CREATE;
}
// Create our folder structure.
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/MacOS");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/MacOS");
}
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Frameworks");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Frameworks");
}
if (err == OK) {
print_line("Creating " + tmp_app_path_name + "/Contents/Resources");
- err = tmp_app_path->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
+ err = tmp_app_dir->make_dir_recursive(tmp_app_path_name + "/Contents/Resources");
}
// Now process our template.
@@ -678,14 +678,14 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name_safe + "/");
+ file = file.replace("/data.mono.osx.64.release_debug/", "/data_" + pkg_name + "/");
}
if (file.find("/data.mono.osx.64.release/") != -1) {
if (p_debug) {
ret = unzGoToNextFile(src_pkg_zip);
continue; // skip
}
- file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name_safe + "/");
+ file = file.replace("/data.mono.osx.64.release/", "/data_" + pkg_name + "/");
}
print_line("ADDING: " + file + " size: " + itos(data.size()));
@@ -694,7 +694,7 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
// Write it into our application bundle.
file = tmp_app_path_name.plus_file(file);
if (err == OK) {
- err = tmp_app_path->make_dir_recursive(file.get_base_dir());
+ err = tmp_app_dir->make_dir_recursive(file.get_base_dir());
}
if (err == OK) {
FileAccess *f = FileAccess::open(file, FileAccess::WRITE);
@@ -797,7 +797,10 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p
}
// Clean up temporary .app dir.
- OS::get_singleton()->move_to_trash(tmp_app_path_name);
+ tmp_app_dir->change_dir(tmp_app_path_name);
+ tmp_app_dir->erase_contents_recursive();
+ tmp_app_dir->change_dir("..");
+ tmp_app_dir->remove(tmp_app_dir_name);
}
return err;
diff --git a/platform/server/detect.py b/platform/server/detect.py
index d9ac357679..bf4744a234 100644
--- a/platform/server/detect.py
+++ b/platform/server/detect.py
@@ -138,14 +138,31 @@ def configure(env):
# freetype depends on libpng and zlib, so bundling one of them while keeping others
# as shared libraries leads to weird issues
- if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]:
+ if (
+ env["builtin_freetype"]
+ or env["builtin_libpng"]
+ or env["builtin_zlib"]
+ or env["builtin_graphite"]
+ or env["builtin_harfbuzz"]
+ ):
env["builtin_freetype"] = True
env["builtin_libpng"] = True
env["builtin_zlib"] = True
+ env["builtin_graphite"] = True
+ env["builtin_harfbuzz"] = True
if not env["builtin_freetype"]:
env.ParseConfig("pkg-config freetype2 --cflags --libs")
+ if not env["builtin_graphite"]:
+ env.ParseConfig("pkg-config graphite2 --cflags --libs")
+
+ if not env["builtin_icu"]:
+ env.ParseConfig("pkg-config icu-uc --cflags --libs")
+
+ if not env["builtin_harfbuzz"]:
+ env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs")
+
if not env["builtin_libpng"]:
env.ParseConfig("pkg-config libpng16 --cflags --libs")
@@ -233,7 +250,17 @@ def configure(env):
env.Append(CPPDEFINES=["SERVER_ENABLED", "UNIX_ENABLED"])
if platform.system() == "Darwin":
- env.Append(LINKFLAGS=["-framework", "Cocoa", "-framework", "Carbon", "-lz", "-framework", "IOKit"])
+ env.Append(
+ LINKFLAGS=[
+ "-framework",
+ "Cocoa",
+ "-framework",
+ "Carbon",
+ "-lz",
+ "-framework",
+ "IOKit",
+ ]
+ )
env.Append(LIBS=["pthread"])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index dfbb734ee4..2581cc3af6 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -2792,6 +2792,24 @@ void DisplayServerWindows::_process_key_events() {
case WM_CHAR: {
// extended keys should only be processed as WM_KEYDOWN message.
if (!KeyMappingWindows::is_extended_key(ke.wParam) && ((i == 0 && ke.uMsg == WM_CHAR) || (i > 0 && key_event_buffer[i - 1].uMsg == WM_CHAR))) {
+ static char32_t prev_wc = 0;
+ char32_t unicode = ke.wParam;
+ if ((unicode & 0xfffffc00) == 0xd800) {
+ if (prev_wc != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wc = unicode;
+ break; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wc == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ break; // Skip invalid surrogate.
+ }
+ unicode = (prev_wc << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wc = 0;
+ } else {
+ prev_wc = 0;
+ }
Ref<InputEventKey> k;
k.instance();
@@ -2803,7 +2821,7 @@ void DisplayServerWindows::_process_key_events() {
k->set_pressed(true);
k->set_keycode(KeyMappingWindows::get_keysym(ke.wParam));
k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
- k->set_unicode(ke.wParam);
+ k->set_unicode(unicode);
if (k->get_unicode() && gr_mem) {
k->set_alt(false);
k->set_control(false);
@@ -2840,7 +2858,25 @@ void DisplayServerWindows::_process_key_events() {
k->set_physical_keycode(KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24)));
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
- k->set_unicode(key_event_buffer[i + 1].wParam);
+ char32_t unicode = key_event_buffer[i + 1].wParam;
+ static char32_t prev_wck = 0;
+ if ((unicode & 0xfffffc00) == 0xd800) {
+ if (prev_wck != 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ }
+ prev_wck = unicode;
+ break; // Skip surrogate.
+ } else if ((unicode & 0xfffffc00) == 0xdc00) {
+ if (prev_wck == 0) {
+ ERR_PRINT("invalid utf16 surrogate input");
+ break; // Skip invalid surrogate.
+ }
+ unicode = (prev_wck << 10UL) + unicode - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev_wck = 0;
+ } else {
+ prev_wck = 0;
+ }
+ k->set_unicode(unicode);
}
if (k->get_unicode() && gr_mem) {
k->set_alt(false);