diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/detect.py | 21 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 17 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.h | 4 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.cpp | 10 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.h | 4 | ||||
-rw-r--r-- | platform/linuxbsd/x11/detect_prime_x11.cpp | 14 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 256 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.h | 3 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.cpp | 9 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.h | 1 |
10 files changed, 299 insertions, 40 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 72bffceb1f..59cc6e7962 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -85,6 +85,16 @@ def configure(env: "Environment"): # gdb works fine without it though, so maybe our crash handler could too. env.Append(LINKFLAGS=["-rdynamic"]) + # Cross-compilation + # TODO: Support cross-compilation on architectures other than x86. + host_is_64_bit = sys.maxsize > 2**32 + if host_is_64_bit and env["arch"] == "x86_32": + env.Append(CCFLAGS=["-m32"]) + env.Append(LINKFLAGS=["-m32"]) + elif not host_is_64_bit and env["arch"] == "x86_64": + env.Append(CCFLAGS=["-m64"]) + env.Append(LINKFLAGS=["-m64"]) + # CPU architecture flags. if env["arch"] == "rv64": # G = General-purpose extensions, C = Compression extension (very common). @@ -469,22 +479,11 @@ def configure(env: "Environment"): if platform.system() == "FreeBSD": env.Append(LINKFLAGS=["-lkvm"]) - ## Cross-compilation - # TODO: Support cross-compilation on architectures other than x86. - host_is_64_bit = sys.maxsize > 2**32 - if host_is_64_bit and env["arch"] == "x86_32": - env.Append(CCFLAGS=["-m32"]) - env.Append(LINKFLAGS=["-m32", "-L/usr/lib/i386-linux-gnu"]) - elif not host_is_64_bit and env["arch"] == "x86_64": - env.Append(CCFLAGS=["-m64"]) - env.Append(LINKFLAGS=["-m64", "-L/usr/lib/i686-linux-gnu"]) - # Link those statically for portability if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) if env["use_llvm"] and platform.system() != "FreeBSD": env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a" - else: if env["use_llvm"] and platform.system() != "FreeBSD": env.Append(LIBS=["atomic"]) diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index cf4354139a..d9aa98ba70 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -427,6 +427,17 @@ Error FreeDesktopPortalDesktop::file_dialog_show(DisplayServer::WindowID p_windo return OK; } +void FreeDesktopPortalDesktop::_file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index) { + Variant ret; + Callable::CallError ce; + const Variant *args[3] = { &p_status, &p_list, &p_index }; + + p_callable.callp(args, 3, ret, ce); + if (ce.error != Callable::CallError::CALL_OK) { + ERR_PRINT(vformat(RTR("Failed to execute file dialogs callback: %s."), Variant::get_callable_error_text(p_callable, args, 3, ce))); + } +} + void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) { FreeDesktopPortalDesktop *portal = (FreeDesktopPortalDesktop *)p_ud; @@ -451,11 +462,7 @@ void FreeDesktopPortalDesktop::_thread_file_dialog_monitor(void *p_ud) { file_chooser_parse_response(&iter, fd.filter_names, cancel, uris, index); if (fd.callback.is_valid()) { - Variant v_status = !cancel; - Variant v_files = uris; - Variant v_index = index; - Variant *v_args[3] = { &v_status, &v_files, &v_index }; - fd.callback.call_deferredp((const Variant **)&v_args, 3); + callable_mp(portal, &FreeDesktopPortalDesktop::_file_dialog_callback).call_deferred(fd.callback, !cancel, uris, index); } if (fd.prev_focus != DisplayServer::INVALID_WINDOW_ID) { callable_mp(DisplayServer::get_singleton(), &DisplayServer::window_move_to_foreground).call_deferred(fd.prev_focus); diff --git a/platform/linuxbsd/freedesktop_portal_desktop.h b/platform/linuxbsd/freedesktop_portal_desktop.h index 503c382207..71e9812ea9 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.h +++ b/platform/linuxbsd/freedesktop_portal_desktop.h @@ -40,7 +40,7 @@ struct DBusMessage; struct DBusConnection; struct DBusMessageIter; -class FreeDesktopPortalDesktop { +class FreeDesktopPortalDesktop : public Object { private: bool unsupported = false; @@ -54,6 +54,8 @@ private: static void append_dbus_dict_bool(DBusMessageIter *p_iter, const String &p_key, bool p_value); static bool file_chooser_parse_response(DBusMessageIter *p_iter, const Vector<String> &p_names, bool &r_cancel, Vector<String> &r_urls, int &r_index); + void _file_dialog_callback(const Callable &p_callable, const Variant &p_status, const Variant &p_list, const Variant &p_index); + struct FileDialogData { Vector<String> filter_names; DBusConnection *connection = nullptr; diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp index 96745ab8ae..46291bb4da 100644 --- a/platform/linuxbsd/tts_linux.cpp +++ b/platform/linuxbsd/tts_linux.cpp @@ -82,11 +82,11 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) { void TTS_Linux::speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark) { TTS_Linux *tts = TTS_Linux::get_singleton(); if (tts) { - callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred(p_msg_id, p_client_id, (int)p_type, String::utf8(p_index_mark)); + callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred((int)p_msg_id, (int)p_type, String::utf8(p_index_mark)); } } -void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark) { +void TTS_Linux::_speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark) { _THREAD_SAFE_METHOD_ if (ids.has(p_msg_id)) { @@ -97,7 +97,7 @@ void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_ty void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type) { TTS_Linux *tts = TTS_Linux::get_singleton(); if (tts) { - callable_mp(tts, &TTS_Linux::_speech_event).call_deferred(p_msg_id, p_client_id, (int)p_type); + callable_mp(tts, &TTS_Linux::_speech_event).call_deferred((int)p_msg_id, (int)p_type); } } @@ -119,7 +119,7 @@ void TTS_Linux::_load_voices() { } } -void TTS_Linux::_speech_event(size_t p_msg_id, size_t p_client_id, int p_type) { +void TTS_Linux::_speech_event(int p_msg_id, int p_type) { _THREAD_SAFE_METHOD_ if (!paused && ids.has(p_msg_id)) { @@ -226,7 +226,7 @@ void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume, if (is_paused()) { resume(); } else { - _speech_event(0, 0, (int)SPD_EVENT_BEGIN); + _speech_event(0, (int)SPD_EVENT_BEGIN); } } diff --git a/platform/linuxbsd/tts_linux.h b/platform/linuxbsd/tts_linux.h index ec68219689..2a3d33221d 100644 --- a/platform/linuxbsd/tts_linux.h +++ b/platform/linuxbsd/tts_linux.h @@ -72,8 +72,8 @@ class TTS_Linux : public Object { protected: void _load_voices(); - void _speech_event(size_t p_msg_id, size_t p_client_id, int p_type); - void _speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark); + void _speech_event(int p_msg_id, int p_type); + void _speech_index_mark(int p_msg_id, int p_type, const String &p_index_mark); public: static TTS_Linux *get_singleton(); diff --git a/platform/linuxbsd/x11/detect_prime_x11.cpp b/platform/linuxbsd/x11/detect_prime_x11.cpp index 2b5776ce54..c2cb02b937 100644 --- a/platform/linuxbsd/x11/detect_prime_x11.cpp +++ b/platform/linuxbsd/x11/detect_prime_x11.cpp @@ -137,6 +137,19 @@ void create_context() { XFree(vi); } +int silent_error_handler(Display *display, XErrorEvent *error) { + static char message[1024]; + XGetErrorText(display, error->error_code, message, sizeof(message)); + print_verbose(vformat("XServer error: %s" + "\n Major opcode of failed request: %d" + "\n Serial number of failed request: %d" + "\n Current serial number in output stream: %d", + String::utf8(message), (uint64_t)error->request_code, (uint64_t)error->minor_code, (uint64_t)error->serial)); + + quick_exit(1); + return 0; +} + int detect_prime() { pid_t p; int priorities[2] = {}; @@ -189,6 +202,7 @@ int detect_prime() { // cleaning up these processes, and fork() makes a copy // of all globals. CoreGlobals::leak_reporting_enabled = false; + XSetErrorHandler(&silent_error_handler); char string[201]; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index fe81da76d3..3bafdfb53d 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -39,6 +39,7 @@ #include "core/math/math_funcs.h" #include "core/string/print_string.h" #include "core/string/ustring.h" +#include "drivers/png/png_driver_common.h" #include "main/main.h" #include "scene/resources/atlas_texture.h" @@ -519,7 +520,7 @@ 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) { + if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue && event->xproperty.atom == *(Atom *)arg) { return True; } else { return False; @@ -593,7 +594,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A // Non-blocking wait for next event and remove it from the queue. XEvent ev; - while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) { + while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, (XPointer)&selection)) { result = XGetWindowProperty(x11_display, x11_window, selection, // selection type 0, LONG_MAX, // offset - len @@ -664,6 +665,74 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A return ret; } +Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_window) const { + Atom target = XInternAtom(x11_display, "TARGETS", 0); + Atom png = XInternAtom(x11_display, "image/png", 0); + Atom *valid_targets = nullptr; + unsigned long atom_count = 0; + + Window selection_owner = XGetSelectionOwner(x11_display, p_source); + if (selection_owner != None && selection_owner != x11_window) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + Atom selection = XA_PRIMARY; + XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); + + 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); + // Do not get any data, see how much data is there. + Atom type; + int format, result; + unsigned long len, bytes_left, dummy; + XGetWindowProperty(x11_display, x11_window, + selection, // Tricky.. + 0, 0, // offset - len + 0, // Delete 0==FALSE + XA_ATOM, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + (unsigned char **)&valid_targets); + + if (valid_targets) { + XFree(valid_targets); + valid_targets = nullptr; + } + + if (type == XA_ATOM && bytes_left > 0) { + // Data is ready and can be processed all at once. + result = XGetWindowProperty(x11_display, x11_window, + selection, 0, bytes_left / 4, 0, + XA_ATOM, &type, &format, + &len, &dummy, (unsigned char **)&valid_targets); + if (result == Success) { + atom_count = len; + } else { + print_verbose("Failed to get selection data."); + return None; + } + } else { + return None; + } + } else { + return None; + } + for (unsigned long i = 0; i < atom_count; i++) { + Atom atom = valid_targets[i]; + if (atom == png) { + XFree(valid_targets); + return png; + } + } + + XFree(valid_targets); + return None; +} + String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const { String ret; Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True); @@ -702,6 +771,158 @@ String DisplayServerX11::clipboard_get_primary() const { return ret; } +Ref<Image> DisplayServerX11::clipboard_get_image() const { + _THREAD_SAFE_METHOD_ + Atom clipboard = XInternAtom(x11_display, "CLIPBOARD", 0); + Window x11_window = windows[MAIN_WINDOW_ID].x11_window; + Ref<Image> ret; + Atom target = _clipboard_get_image_target(clipboard, x11_window); + if (target == None) { + return ret; + } + + Window selection_owner = XGetSelectionOwner(x11_display, clipboard); + + if (selection_owner != None && selection_owner != x11_window) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + // Identifier for the property the other window + // will send the converted data to. + Atom transfer_prop = XA_PRIMARY; + XConvertSelection(x11_display, + clipboard, // source selection + target, // format to convert to + transfer_prop, // output property + x11_window, CurrentTime); + + 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); + + // 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, + transfer_prop, // Property data is transferred through + 0, 1, // offset, len (4 so we can get the size if INCR is used) + 0, // Delete 0==FALSE + AnyPropertyType, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + &data); + + if (type == XInternAtom(x11_display, "INCR", 0)) { + ERR_FAIL_COND_V_MSG(len != 1, ret, "Incremental transfer initial value was not length."); + + // 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; + + // Initial response is the lower bound of the length of the transferred data. + incr_data.resize(*(unsigned long *)data); + XFree(data); + data = nullptr; + + // Delete INCR property to notify the owner. + XDeleteProperty(x11_display, x11_window, transfer_prop); + + // 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, (XPointer)&transfer_prop)) { + result = XGetWindowProperty(x11_display, x11_window, + transfer_prop, // output property + 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(); + // 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 if (!(format == 0 && len == 0)) { + // For unclear reasons the first GetWindowProperty always returns a length and format of 0. + // Otherwise, last chunk, process finished. + done = true; + success = true; + } + } else { + print_verbose("Failed to get selection data chunk."); + done = true; + } + + if (data) { + XFree(data); + data = nullptr; + } + + if (done) { + break; + } + } + } + + if (success && (data_size > 0)) { + ret.instantiate(); + PNGDriverCommon::png_to_image(incr_data.ptr(), incr_data.size(), false, ret); + } + } else if (bytes_left > 0) { + if (data) { + XFree(data); + data = nullptr; + } + // Data is ready and can be processed all at once. + result = XGetWindowProperty(x11_display, x11_window, + transfer_prop, 0, bytes_left + 4, 0, + AnyPropertyType, &type, &format, + &len, &dummy, &data); + if (result == Success) { + ret.instantiate(); + PNGDriverCommon::png_to_image((uint8_t *)data, bytes_left, false, ret); + } else { + print_verbose("Failed to get selection data."); + } + + if (data) { + XFree(data); + } + } + } + + return ret; +} + +bool DisplayServerX11::clipboard_has_image() const { + Atom target = _clipboard_get_image_target( + XInternAtom(x11_display, "CLIPBOARD", 0), + windows[MAIN_WINDOW_ID].x11_window); + return target != None; +} + Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) { if (event->xany.window == *(Window *)arg) { return (event->type == SelectionRequest) || @@ -1350,7 +1571,7 @@ float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { //Use xrandr to get screen refresh rate. if (xrandr_ext_ok) { - XRRScreenResources *screen_info = XRRGetScreenResources(x11_display, windows[MAIN_WINDOW_ID].x11_window); + XRRScreenResources *screen_info = XRRGetScreenResourcesCurrent(x11_display, windows[MAIN_WINDOW_ID].x11_window); if (screen_info) { RRMode current_mode = 0; xrr_monitor_info *monitors = nullptr; @@ -5844,33 +6065,36 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } if (rendering_driver == "opengl3") { - GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE; - - gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type)); - - if (gl_manager->initialize(x11_display) != OK) { + gl_manager = memnew(GLManager_X11(p_resolution, GLManager_X11::GLES_3_0_COMPATIBLE)); + if (gl_manager->initialize(x11_display) != OK || gl_manager->open_display(x11_display) != OK) { memdelete(gl_manager); gl_manager = nullptr; - r_error = ERR_UNAVAILABLE; - return; + bool fallback = GLOBAL_GET("rendering/gl_compatibility/fallback_to_gles"); + if (fallback) { + WARN_PRINT("Your video card drivers seem not to support the required OpenGL version, switching to OpenGLES."); + rendering_driver = "opengl3_es"; + } else { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Could not initialize OpenGL."); + } + } else { + driver_found = true; + RasterizerGLES3::make_current(true); } - driver_found = true; - - RasterizerGLES3::make_current(true); } + if (rendering_driver == "opengl3_es") { gl_manager_egl = memnew(GLManagerEGL_X11); - if (gl_manager_egl->initialize() != OK) { memdelete(gl_manager_egl); gl_manager_egl = nullptr; r_error = ERR_UNAVAILABLE; - return; + ERR_FAIL_MSG("Could not initialize OpenGLES."); } driver_found = true; - RasterizerGLES3::make_current(false); } + #endif if (!driver_found) { r_error = ERR_UNAVAILABLE; diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index 9706a4aa11..a8d134a6c7 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -304,6 +304,7 @@ class DisplayServerX11 : public DisplayServer { String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const; String _clipboard_get(Atom p_source, Window x11_window) const; + Atom _clipboard_get_image_target(Atom p_source, Window x11_window) const; void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const; bool do_mouse_warp = false; @@ -408,6 +409,8 @@ public: virtual void clipboard_set(const String &p_text) override; virtual String clipboard_get() const override; + virtual Ref<Image> clipboard_get_image() const override; + virtual bool clipboard_has_image() const override; virtual void clipboard_set_primary(const String &p_text) override; virtual String clipboard_get_primary() const override; diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp index 95947301cf..602dd784e0 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.cpp +++ b/platform/linuxbsd/x11/gl_manager_x11.cpp @@ -208,6 +208,15 @@ XVisualInfo GLManager_X11::get_vi(Display *p_display, Error &r_error) { return _displays[display_id].x_vi; } +Error GLManager_X11::open_display(Display *p_display) { + int gldisplay_id = _find_or_create_display(p_display); + if (gldisplay_id < 0) { + return ERR_CANT_CREATE; + } else { + return OK; + } +} + Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { // make sure vector is big enough... // we can mirror the external vector, it is simpler diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h index d3a25506a8..235c7d22f9 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.h +++ b/platform/linuxbsd/x11/gl_manager_x11.h @@ -129,6 +129,7 @@ public: void *get_glx_context(DisplayServer::WindowID p_window_id); + Error open_display(Display *p_display); GLManager_X11(const Vector2i &p_size, ContextType p_context_type); ~GLManager_X11(); }; |