diff options
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r-- | platform/linuxbsd/detect.py | 25 | ||||
-rw-r--r-- | platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml | 73 | ||||
-rw-r--r-- | platform/linuxbsd/export/export.cpp | 4 | ||||
-rw-r--r-- | platform/linuxbsd/export/export.h | 1 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.cpp | 42 | ||||
-rw-r--r-- | platform/linuxbsd/export/export_plugin.h | 5 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_portal_desktop.cpp | 11 | ||||
-rw-r--r-- | platform/linuxbsd/freedesktop_screensaver.cpp | 11 | ||||
-rw-r--r-- | platform/linuxbsd/joypad_linux.cpp | 8 | ||||
-rw-r--r-- | platform/linuxbsd/os_linuxbsd.cpp | 147 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.cpp | 5 | ||||
-rw-r--r-- | platform/linuxbsd/tts_linux.h | 2 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.cpp | 274 | ||||
-rw-r--r-- | platform/linuxbsd/x11/display_server_x11.h | 6 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.cpp | 23 | ||||
-rw-r--r-- | platform/linuxbsd/x11/gl_manager_x11.h | 2 | ||||
-rw-r--r-- | platform/linuxbsd/x11/key_mapping_x11.cpp | 44 |
17 files changed, 498 insertions, 185 deletions
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 3f713d2db3..dadc03685b 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -56,6 +56,16 @@ def get_opts(): ] +def get_doc_classes(): + return [ + "EditorExportPlatformLinuxBSD", + ] + + +def get_doc_path(): + return "doc_classes" + + def get_flags(): return [ ("arch", detect_arch()), @@ -70,7 +80,7 @@ def configure(env: "Environment"): 'Unsupported CPU architecture "%s" for Linux / *BSD. Supported architectures are: %s.' % (env["arch"], ", ".join(supported_arches)) ) - sys.exit() + sys.exit(255) ## Build type @@ -208,7 +218,7 @@ def configure(env: "Environment"): "freetype, libpng, zlib, graphite, harfbuzz.\n" "Please specify `builtin_<name>=no` for all of them, or none." ) - sys.exit() + sys.exit(255) if not env["builtin_freetype"]: env.ParseConfig("pkg-config freetype2 --cflags --libs") @@ -277,11 +287,10 @@ def configure(env: "Environment"): env.Prepend(CPPPATH=["/usr/include/recastnavigation"]) env.Append(LIBS=["Recast"]) - if not env["builtin_embree"]: + if not env["builtin_embree"] and env["arch"] in ["x86_64", "arm64"]: # No pkgconfig file so far, hardcode expected lib name. env.Append(LIBS=["embree3"]) - ## Flags if env["fontconfig"]: if not env["use_sowrap"]: if os.system("pkg-config --exists fontconfig") == 0: # 0 means found @@ -308,11 +317,12 @@ def configure(env: "Environment"): if not env["use_sowrap"]: if os.system("pkg-config --exists libpulse") == 0: # 0 means found env.ParseConfig("pkg-config libpulse --cflags --libs") - env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED", "_REENTRANT"]) + env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"]) else: print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.") env["pulseaudio"] = False - env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED", "_REENTRANT"]) + else: + env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED", "_REENTRANT"]) if env["dbus"]: if not env["use_sowrap"]: @@ -453,6 +463,9 @@ def configure(env: "Environment"): else: env.Append(LINKFLAGS=["-T", "platform/linuxbsd/pck_embed.legacy.ld"]) + 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 diff --git a/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml new file mode 100644 index 0000000000..4ab2464929 --- /dev/null +++ b/platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="EditorExportPlatformLinuxBSD" inherits="EditorExportPlatformPC" version="4.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Exporter for Linux/BSD. + </brief_description> + <description> + </description> + <tutorials> + <link title="Exporting for Linux">$DOCS_URL/tutorials/export/exporting_for_linux.html</link> + </tutorials> + <members> + <member name="binary_format/architecture" type="String" setter="" getter=""> + Application executable architecture. + Supported architectures: [code]x86_32[/code], [code]x86_64[/code], [code]arm64[/code], [code]arm32[/code], [code]rv64[/code], [code]ppc64[/code], and [code]ppc32[/code]. + Official export templates include [code]x86_32[/code] and [code]x86_64[/code] binaries only. + </member> + <member name="binary_format/embed_pck" type="bool" setter="" getter=""> + If [code]true[/code], project resources are embedded into the executable. + </member> + <member name="custom_template/debug" type="String" setter="" getter=""> + Path to the custom export template. If left empty, default template is used. + </member> + <member name="custom_template/release" type="String" setter="" getter=""> + Path to the custom export template. If left empty, default template is used. + </member> + <member name="debug/export_console_script" type="int" setter="" getter=""> + If [code]true[/code], a console wrapper script is exported alongside the main executable, which allows running the project with enabled console output. + </member> + <member name="ssh_remote_deploy/cleanup_script" type="String" setter="" getter=""> + Script code to execute on the remote host when app is finished. + The following variables can be used in the script: + - [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to. + - [code]{archive_name}[/code] - Name of the ZIP containing uploaded application. + - [code]{exe_name}[/code] - Name of application executable. + - [code]{cmd_args}[/code] - Array of the command line argument for the application. + </member> + <member name="ssh_remote_deploy/enabled" type="bool" setter="" getter=""> + Enables remote deploy using SSH/SCP. + </member> + <member name="ssh_remote_deploy/extra_args_scp" type="String" setter="" getter=""> + Array of the additional command line arguments passed to the SCP. + </member> + <member name="ssh_remote_deploy/extra_args_ssh" type="String" setter="" getter=""> + Array of the additional command line arguments passed to the SSH. + </member> + <member name="ssh_remote_deploy/host" type="String" setter="" getter=""> + Remote host SSH user name and address, in [code]user@address[/code] format. + </member> + <member name="ssh_remote_deploy/port" type="String" setter="" getter=""> + Remote host SSH port number. + </member> + <member name="ssh_remote_deploy/run_script" type="String" setter="" getter=""> + Script code to execute on the remote host when running the app. + The following variables can be used in the script: + - [code]{temp_dir}[/code] - Path of temporary folder on the remote, used to upload app and scripts to. + - [code]{archive_name}[/code] - Name of the ZIP containing uploaded application. + - [code]{exe_name}[/code] - Name of application executable. + - [code]{cmd_args}[/code] - Array of the command line argument for the application. + </member> + <member name="texture_format/bptc" type="bool" setter="" getter=""> + If [code]true[/code], project textures are exported in the BPTC format. + </member> + <member name="texture_format/etc" type="bool" setter="" getter=""> + If [code]true[/code], project textures are exported in the ETC format. + </member> + <member name="texture_format/etc2" type="bool" setter="" getter=""> + If [code]true[/code], project textures are exported in the ETC2 format. + </member> + <member name="texture_format/s3tc" type="bool" setter="" getter=""> + If [code]true[/code], project textures are exported in the S3TC format. + </member> + </members> +</class> diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 2c5a945b6c..09f354246d 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -33,6 +33,10 @@ #include "editor/export/editor_export.h" #include "export_plugin.h" +void register_linuxbsd_exporter_types() { + GDREGISTER_VIRTUAL_CLASS(EditorExportPlatformLinuxBSD); +} + void register_linuxbsd_exporter() { Ref<EditorExportPlatformLinuxBSD> platform; platform.instantiate(); diff --git a/platform/linuxbsd/export/export.h b/platform/linuxbsd/export/export.h index a2d70a73e3..f493047815 100644 --- a/platform/linuxbsd/export/export.h +++ b/platform/linuxbsd/export/export.h @@ -31,6 +31,7 @@ #ifndef LINUXBSD_EXPORT_H #define LINUXBSD_EXPORT_H +void register_linuxbsd_exporter_types(); void register_linuxbsd_exporter(); #endif // LINUXBSD_EXPORT_H diff --git a/platform/linuxbsd/export/export_plugin.cpp b/platform/linuxbsd/export/export_plugin.cpp index 2528bb2b99..9544cc761d 100644 --- a/platform/linuxbsd/export/export_plugin.cpp +++ b/platform/linuxbsd/export/export_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_scale.h" +#include "editor/export/editor_export.h" #include "platform/linuxbsd/logo_svg.gen.h" #include "platform/linuxbsd/run_icon_svg.gen.h" @@ -142,7 +143,18 @@ List<String> EditorExportPlatformLinuxBSD::get_binary_extensions(const Ref<Edito return list; } -void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) { +bool EditorExportPlatformLinuxBSD::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const { + if (p_preset) { + // Hide SSH options. + bool ssh = p_preset->get("ssh_remote_deploy/enabled"); + if (!ssh && p_option != "ssh_remote_deploy/enabled" && p_option.begins_with("ssh_remote_deploy/")) { + return false; + } + } + return true; +} + +void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_options) const { EditorExportPlatformPC::get_export_options(r_options); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "binary_format/architecture", PROPERTY_HINT_ENUM, "x86_64,x86_32,arm64,arm32,rv64,ppc64,ppc32"), "x86_64")); @@ -156,7 +168,7 @@ void EditorExportPlatformLinuxBSD::get_export_options(List<ExportOption> *r_opti "kill $(pgrep -x -f \"{temp_dir}/{exe_name} {cmd_args}\")\n" "rm -rf \"{temp_dir}\""; - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "ssh_remote_deploy/enabled"), false, true)); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/host"), "user@host_ip")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "ssh_remote_deploy/port"), "22")); @@ -503,22 +515,24 @@ Error EditorExportPlatformLinuxBSD::run(const Ref<EditorExportPreset> &p_preset, } EditorExportPlatformLinuxBSD::EditorExportPlatformLinuxBSD() { + if (EditorNode::get_singleton()) { #ifdef MODULE_SVG_ENABLED - Ref<Image> img = memnew(Image); - const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); + Ref<Image> img = memnew(Image); + const bool upsample = !Math::is_equal_approx(Math::round(EDSCALE), EDSCALE); - ImageLoaderSVG img_loader; - img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); - set_logo(ImageTexture::create_from_image(img)); + ImageLoaderSVG img_loader; + img_loader.create_image_from_string(img, _linuxbsd_logo_svg, EDSCALE, upsample, false); + set_logo(ImageTexture::create_from_image(img)); - img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); - run_icon = ImageTexture::create_from_image(img); + img_loader.create_image_from_string(img, _linuxbsd_run_icon_svg, EDSCALE, upsample, false); + run_icon = ImageTexture::create_from_image(img); #endif - Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); - } else { - stop_icon.instantiate(); + Ref<Theme> theme = EditorNode::get_singleton()->get_editor_theme(); + if (theme.is_valid()) { + stop_icon = theme->get_icon(SNAME("Stop"), SNAME("EditorIcons")); + } else { + stop_icon.instantiate(); + } } } diff --git a/platform/linuxbsd/export/export_plugin.h b/platform/linuxbsd/export/export_plugin.h index 4f860c3fd0..cef714e86e 100644 --- a/platform/linuxbsd/export/export_plugin.h +++ b/platform/linuxbsd/export/export_plugin.h @@ -37,6 +37,8 @@ #include "scene/resources/texture.h" class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { + GDCLASS(EditorExportPlatformLinuxBSD, EditorExportPlatformPC); + HashMap<String, String> extensions; struct SSHCleanupCommand { @@ -69,8 +71,9 @@ class EditorExportPlatformLinuxBSD : public EditorExportPlatformPC { Error _export_debug_script(const Ref<EditorExportPreset> &p_preset, const String &p_app_name, const String &p_pkg_name, const String &p_path); public: - virtual void get_export_options(List<ExportOption> *r_options) override; + virtual void get_export_options(List<ExportOption> *r_options) const override; virtual List<String> get_binary_extensions(const Ref<EditorExportPreset> &p_preset) const override; + virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override; virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; virtual String get_template_file_name(const String &p_target, const String &p_arch) const override; virtual Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, int64_t p_embedded_size) override; diff --git a/platform/linuxbsd/freedesktop_portal_desktop.cpp b/platform/linuxbsd/freedesktop_portal_desktop.cpp index ec1fcf6698..b45b7e676d 100644 --- a/platform/linuxbsd/freedesktop_portal_desktop.cpp +++ b/platform/linuxbsd/freedesktop_portal_desktop.cpp @@ -138,6 +138,17 @@ FreeDesktopPortalDesktop::FreeDesktopPortalDesktop() { #else unsupported = false; #endif + bool ver_ok = false; + int version_major = 0; + int version_minor = 0; + int version_rev = 0; + dbus_get_version(&version_major, &version_minor, &version_rev); + ver_ok = (version_major == 1 && version_minor >= 10) || (version_major > 1); // 1.10.0 + print_verbose(vformat("PortalDesktop: DBus %d.%d.%d detected.", version_major, version_minor, version_rev)); + if (!ver_ok) { + print_verbose("PortalDesktop: Unsupported DBus library version!"); + unsupported = true; + } } #endif // DBUS_ENABLED diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp index d07e781a5f..78f2337599 100644 --- a/platform/linuxbsd/freedesktop_screensaver.cpp +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -141,6 +141,17 @@ FreeDesktopScreenSaver::FreeDesktopScreenSaver() { #else unsupported = false; #endif + bool ver_ok = false; + int version_major = 0; + int version_minor = 0; + int version_rev = 0; + dbus_get_version(&version_major, &version_minor, &version_rev); + ver_ok = (version_major == 1 && version_minor >= 10) || (version_major > 1); // 1.10.0 + print_verbose(vformat("ScreenSaver: DBus %d.%d.%d detected.", version_major, version_minor, version_rev)); + if (!ver_ok) { + print_verbose("ScreenSaver:: Unsupported DBus library version!"); + unsupported = true; + } } #endif // DBUS_ENABLED diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 0256af0a59..5c623b8ba2 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -82,7 +82,13 @@ JoypadLinux::JoypadLinux(Input *in) { #endif use_udev = initialize_libudev(dylibloader_verbose) == 0; if (use_udev) { - print_verbose("JoypadLinux: udev enabled and loaded successfully."); + if (!udev_new || !udev_unref || !udev_enumerate_new || !udev_enumerate_add_match_subsystem || !udev_enumerate_scan_devices || !udev_enumerate_get_list_entry || !udev_list_entry_get_next || !udev_list_entry_get_name || !udev_device_new_from_syspath || !udev_device_get_devnode || !udev_device_get_action || !udev_device_unref || !udev_enumerate_unref || !udev_monitor_new_from_netlink || !udev_monitor_filter_add_match_subsystem_devtype || !udev_monitor_enable_receiving || !udev_monitor_get_fd || !udev_monitor_receive_device || !udev_monitor_unref) { + // There's no API to check version, check if functions are available instead. + use_udev = false; + print_verbose("JoypadLinux: Unsupported udev library version!"); + } else { + print_verbose("JoypadLinux: udev enabled and loaded successfully."); + } } else { print_verbose("JoypadLinux: udev enabled, but couldn't be loaded. Falling back to /dev/input to detect joypads."); } diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index 54bb34ef73..11c81be4a9 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -677,40 +677,45 @@ Vector<String> OS_LinuxBSD::get_system_font_path_for_text(const String &p_font_n } Vector<String> ret; - FcPattern *pattern = FcPatternCreate(); - if (pattern) { - FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); - FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); - FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); - FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); - - FcCharSet *char_set = FcCharSetCreate(); - for (int i = 0; i < p_text.size(); i++) { - FcCharSetAddChar(char_set, p_text[i]); - } - FcPatternAddCharSet(pattern, FC_CHARSET, char_set); - - FcLangSet *lang_set = FcLangSetCreate(); - FcLangSetAdd(lang_set, reinterpret_cast<const FcChar8 *>(p_locale.utf8().get_data())); - FcPatternAddLangSet(pattern, FC_LANG, lang_set); - - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcResult result; - FcPattern *match = FcFontMatch(0, pattern, &result); - if (match) { - char *file_name = nullptr; - if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { - if (file_name) { - ret.push_back(String::utf8(file_name)); + static const char *allowed_formats[] = { "TrueType", "CFF" }; + for (size_t i = 0; i < sizeof(allowed_formats) / sizeof(const char *); i++) { + FcPattern *pattern = FcPatternCreate(); + if (pattern) { + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); + FcPatternAddString(pattern, FC_FONTFORMAT, reinterpret_cast<const FcChar8 *>(allowed_formats[i])); + FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); + FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); + FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); + FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); + + FcCharSet *char_set = FcCharSetCreate(); + for (int j = 0; j < p_text.size(); j++) { + FcCharSetAddChar(char_set, p_text[j]); + } + FcPatternAddCharSet(pattern, FC_CHARSET, char_set); + + FcLangSet *lang_set = FcLangSetCreate(); + FcLangSetAdd(lang_set, reinterpret_cast<const FcChar8 *>(p_locale.utf8().get_data())); + FcPatternAddLangSet(pattern, FC_LANG, lang_set); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern *match = FcFontMatch(0, pattern, &result); + if (match) { + char *file_name = nullptr; + if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { + if (file_name) { + ret.push_back(String::utf8(file_name)); + } } + FcPatternDestroy(match); } - FcPatternDestroy(match); + FcPatternDestroy(pattern); + FcCharSetDestroy(char_set); + FcLangSetDestroy(lang_set); } - FcPatternDestroy(pattern); - FcCharSetDestroy(char_set); - FcLangSetDestroy(lang_set); } return ret; @@ -725,47 +730,51 @@ String OS_LinuxBSD::get_system_font_path(const String &p_font_name, int p_weight ERR_FAIL_V_MSG(String(), "Unable to load fontconfig, system font support is disabled."); } - String ret; - FcPattern *pattern = FcPatternCreate(); - if (pattern) { - bool allow_substitutes = (p_font_name.to_lower() == "sans-serif") || (p_font_name.to_lower() == "serif") || (p_font_name.to_lower() == "monospace") || (p_font_name.to_lower() == "cursive") || (p_font_name.to_lower() == "fantasy"); - - FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); - FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); - FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); - FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); - FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); - - FcConfigSubstitute(0, pattern, FcMatchPattern); - FcDefaultSubstitute(pattern); - - FcResult result; - FcPattern *match = FcFontMatch(0, pattern, &result); - if (match) { - if (!allow_substitutes) { - char *family_name = nullptr; - if (FcPatternGetString(match, FC_FAMILY, 0, reinterpret_cast<FcChar8 **>(&family_name)) == FcResultMatch) { - if (family_name && String::utf8(family_name).to_lower() != p_font_name.to_lower()) { + static const char *allowed_formats[] = { "TrueType", "CFF" }; + for (size_t i = 0; i < sizeof(allowed_formats) / sizeof(const char *); i++) { + FcPattern *pattern = FcPatternCreate(); + if (pattern) { + bool allow_substitutes = (p_font_name.to_lower() == "sans-serif") || (p_font_name.to_lower() == "serif") || (p_font_name.to_lower() == "monospace") || (p_font_name.to_lower() == "cursive") || (p_font_name.to_lower() == "fantasy"); + + FcPatternAddBool(pattern, FC_SCALABLE, FcTrue); + FcPatternAddString(pattern, FC_FONTFORMAT, reinterpret_cast<const FcChar8 *>(allowed_formats[i])); + FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(p_font_name.utf8().get_data())); + FcPatternAddInteger(pattern, FC_WEIGHT, _weight_to_fc(p_weight)); + FcPatternAddInteger(pattern, FC_WIDTH, _stretch_to_fc(p_stretch)); + FcPatternAddInteger(pattern, FC_SLANT, p_italic ? FC_SLANT_ITALIC : FC_SLANT_ROMAN); + + FcConfigSubstitute(0, pattern, FcMatchPattern); + FcDefaultSubstitute(pattern); + + FcResult result; + FcPattern *match = FcFontMatch(0, pattern, &result); + if (match) { + if (!allow_substitutes) { + char *family_name = nullptr; + if (FcPatternGetString(match, FC_FAMILY, 0, reinterpret_cast<FcChar8 **>(&family_name)) == FcResultMatch) { + if (family_name && String::utf8(family_name).to_lower() != p_font_name.to_lower()) { + FcPatternDestroy(match); + FcPatternDestroy(pattern); + continue; + } + } + } + char *file_name = nullptr; + if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { + if (file_name) { + String ret = String::utf8(file_name); FcPatternDestroy(match); FcPatternDestroy(pattern); - - return String(); + return ret; } } + FcPatternDestroy(match); } - char *file_name = nullptr; - if (FcPatternGetString(match, FC_FILE, 0, reinterpret_cast<FcChar8 **>(&file_name)) == FcResultMatch) { - if (file_name) { - ret = String::utf8(file_name); - } - } - - FcPatternDestroy(match); + FcPatternDestroy(pattern); } - FcPatternDestroy(pattern); } - return ret; + return String(); #else ERR_FAIL_V_MSG(String(), "Godot was compiled without fontconfig, system font support is disabled."); #endif @@ -1094,6 +1103,16 @@ OS_LinuxBSD::OS_LinuxBSD() { font_config_initialized = true; #endif if (font_config_initialized) { + bool ver_ok = false; + int version = FcGetVersion(); + ver_ok = ((version / 100 / 100) == 2 && (version / 100 % 100) >= 11) || ((version / 100 / 100) > 2); // 2.11.0 + print_verbose(vformat("FontConfig %d.%d.%d detected.", version / 100 / 100, version / 100 % 100, version % 100)); + if (!ver_ok) { + font_config_initialized = false; + } + } + + if (font_config_initialized) { config = FcInitLoadConfigAndFonts(); if (!config) { font_config_initialized = false; diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp index ce0199e87f..a0cb4f5c6c 100644 --- a/platform/linuxbsd/tts_linux.cpp +++ b/platform/linuxbsd/tts_linux.cpp @@ -48,6 +48,11 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) { if (initialize_speechd(dylibloader_verbose) != 0) { print_verbose("Text-to-Speech: Cannot load Speech Dispatcher library!"); } else { + if (!spd_open || !spd_set_notification_on || !spd_list_synthesis_voices || !free_spd_voices || !spd_set_synthesis_voice || !spd_set_volume || !spd_set_voice_pitch || !spd_set_voice_rate || !spd_set_data_mode || !spd_say || !spd_pause || !spd_resume || !spd_cancel) { + // There's no API to check version, check if functions are available instead. + print_verbose("Text-to-Speech: Unsupported Speech Dispatcher library version!"); + return; + } #else { #endif diff --git a/platform/linuxbsd/tts_linux.h b/platform/linuxbsd/tts_linux.h index 4134f8fa2f..651a64d9d6 100644 --- a/platform/linuxbsd/tts_linux.h +++ b/platform/linuxbsd/tts_linux.h @@ -34,8 +34,8 @@ #include "core/os/thread.h" #include "core/os/thread_safe.h" #include "core/string/ustring.h" +#include "core/templates/hash_map.h" #include "core/templates/list.h" -#include "core/templates/rb_map.h" #include "core/variant/array.h" #include "servers/display_server.h" diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index dff2f536a8..ac4fbe2068 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -128,6 +128,7 @@ bool DisplayServerX11::has_feature(Feature p_feature) const { #endif case FEATURE_CLIPBOARD_PRIMARY: case FEATURE_TEXT_TO_SPEECH: + case FEATURE_SCREEN_CAPTURE: return true; default: { } @@ -604,7 +605,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A success = true; } } else { - printf("Failed to get selection data chunk.\n"); + print_verbose("Failed to get selection data chunk."); done = true; } @@ -631,7 +632,7 @@ String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, A if (result == Success) { ret.parse_utf8((const char *)data); } else { - printf("Failed to get selection data.\n"); + print_verbose("Failed to get selection data."); } if (data) { @@ -752,23 +753,56 @@ int DisplayServerX11::get_screen_count() const { } int DisplayServerX11::get_primary_screen() const { - return XDefaultScreen(x11_display); + int event_base, error_base; + if (XineramaQueryExtension(x11_display, &event_base, &error_base)) { + return 0; + } else { + return XDefaultScreen(x11_display); + } } -Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { - Rect2i rect(0, 0, 0, 0); +int DisplayServerX11::get_keyboard_focus_screen() const { + int count = get_screen_count(); + if (count < 2) { + // Early exit with single monitor. + return 0; + } - switch (p_screen) { - case SCREEN_PRIMARY: { - p_screen = get_primary_screen(); - } break; - case SCREEN_OF_MAIN_WINDOW: { - p_screen = window_get_current_screen(MAIN_WINDOW_ID); - } break; - default: - break; + Window focus = 0; + int revert_to = 0; + + XGetInputFocus(x11_display, &focus, &revert_to); + if (focus) { + Window focus_child = 0; + int x = 0, y = 0; + XTranslateCoordinates(x11_display, focus, DefaultRootWindow(x11_display), 0, 0, &x, &y, &focus_child); + + XWindowAttributes xwa; + XGetWindowAttributes(x11_display, focus, &xwa); + Rect2i window_rect = Rect2i(x, y, xwa.width, xwa.height); + + // Find which monitor has the largest overlap with the given window. + int screen_index = 0; + int max_area = 0; + for (int i = 0; i < count; i++) { + Rect2i screen_rect = _screen_get_rect(i); + Rect2i intersection = screen_rect.intersection(window_rect); + int area = intersection.get_area(); + if (area > max_area) { + max_area = area; + screen_index = i; + } + } + return screen_index; } + return get_primary_screen(); +} + +Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { + Rect2i rect(0, 0, 0, 0); + + p_screen = _get_screen_index(p_screen); ERR_FAIL_COND_V(p_screen < 0, rect); // Using Xinerama Extension. @@ -833,17 +867,7 @@ int bad_window_error_handler(Display *display, XErrorEvent *error) { Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { _THREAD_SAFE_METHOD_ - switch (p_screen) { - case SCREEN_PRIMARY: { - p_screen = get_primary_screen(); - } break; - case SCREEN_OF_MAIN_WINDOW: { - p_screen = window_get_current_screen(MAIN_WINDOW_ID); - } break; - default: - break; - } - + p_screen = _get_screen_index(p_screen); int screen_count = get_screen_count(); // Check if screen is valid. @@ -1120,18 +1144,7 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { int DisplayServerX11::screen_get_dpi(int p_screen) const { _THREAD_SAFE_METHOD_ - switch (p_screen) { - case SCREEN_PRIMARY: { - p_screen = get_primary_screen(); - } break; - case SCREEN_OF_MAIN_WINDOW: { - p_screen = window_get_current_screen(MAIN_WINDOW_ID); - } break; - default: - break; - } - - //invalid screen? + p_screen = _get_screen_index(p_screen); ERR_FAIL_INDEX_V(p_screen, get_screen_count(), 0); //Get physical monitor Dimensions through XRandR and calculate dpi @@ -1169,21 +1182,33 @@ int DisplayServerX11::screen_get_dpi(int p_screen) const { return 96; } -float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { - _THREAD_SAFE_METHOD_ +Color DisplayServerX11::screen_get_pixel(const Point2i &p_position) const { + Point2i pos = p_position; - switch (p_screen) { - case SCREEN_PRIMARY: { - p_screen = get_primary_screen(); - } break; - case SCREEN_OF_MAIN_WINDOW: { - p_screen = window_get_current_screen(MAIN_WINDOW_ID); - } break; - default: - break; + int number_of_screens = XScreenCount(x11_display); + for (int i = 0; i < number_of_screens; i++) { + Window root = XRootWindow(x11_display, i); + XWindowAttributes root_attrs; + XGetWindowAttributes(x11_display, root, &root_attrs); + if ((pos.x >= root_attrs.x) && (pos.x <= root_attrs.x + root_attrs.width) && (pos.y >= root_attrs.y) && (pos.y <= root_attrs.y + root_attrs.height)) { + XImage *image = XGetImage(x11_display, root, pos.x, pos.y, 1, 1, AllPlanes, XYPixmap); + if (image) { + XColor c; + c.pixel = XGetPixel(image, 0, 0); + XFree(image); + XQueryColor(x11_display, XDefaultColormap(x11_display, i), &c); + return Color(float(c.red) / 65535.0, float(c.green) / 65535.0, float(c.blue) / 65535.0, 1.0); + } + } } - //invalid screen? + return Color(); +} + +float DisplayServerX11::screen_get_refresh_rate(int p_screen) const { + _THREAD_SAFE_METHOD_ + + p_screen = _get_screen_index(p_screen); ERR_FAIL_INDEX_V(p_screen, get_screen_count(), SCREEN_REFRESH_RATE_FALLBACK); //Use xrandr to get screen refresh rate. @@ -1330,7 +1355,7 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { } XDestroyWindow(x11_display, wd.x11_xim_window); #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (wd.xkb_state) { xkb_compose_state_unref(wd.xkb_state); wd.xkb_state = nullptr; @@ -1546,18 +1571,7 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - switch (p_screen) { - case SCREEN_PRIMARY: { - p_screen = get_primary_screen(); - } break; - case SCREEN_OF_MAIN_WINDOW: { - p_screen = window_get_current_screen(MAIN_WINDOW_ID); - } break; - default: - break; - } - - // Check if screen is valid + p_screen = _get_screen_index(p_screen); ERR_FAIL_INDEX(p_screen, get_screen_count()); if (window_get_current_screen(p_window) == p_screen) { @@ -2630,16 +2644,12 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu } Ref<Texture2D> texture = p_cursor; + ERR_FAIL_COND(!texture.is_valid()); Ref<AtlasTexture> atlas_texture = p_cursor; - Ref<Image> image; Size2i texture_size; Rect2i atlas_rect; - if (texture.is_valid()) { - image = texture->get_image(); - } - - if (!image.is_valid() && atlas_texture.is_valid()) { + if (atlas_texture.is_valid()) { texture = atlas_texture->get_atlas(); atlas_rect.size.width = texture->get_width(); @@ -2649,19 +2659,23 @@ void DisplayServerX11::cursor_set_custom_image(const Ref<Resource> &p_cursor, Cu texture_size.width = atlas_texture->get_region().size.x; texture_size.height = atlas_texture->get_region().size.y; - } else if (image.is_valid()) { + } else { texture_size.width = texture->get_width(); texture_size.height = texture->get_height(); } - ERR_FAIL_COND(!texture.is_valid()); ERR_FAIL_COND(p_hotspot.x < 0 || p_hotspot.y < 0); ERR_FAIL_COND(texture_size.width > 256 || texture_size.height > 256); ERR_FAIL_COND(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height); - image = texture->get_image(); + Ref<Image> image = texture->get_image(); ERR_FAIL_COND(!image.is_valid()); + if (image->is_compressed()) { + image = image->duplicate(true); + Error err = image->decompress(); + ERR_FAIL_COND_MSG(err != OK, "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock."); + } // Create the cursor structure XcursorImage *cursor_image = XcursorImageCreate(texture_size.width, texture_size.height); @@ -2824,7 +2838,7 @@ Key DisplayServerX11::keyboard_get_keycode_from_physical(Key p_keycode) const { Key modifiers = p_keycode & KeyModifierMask::MODIFIER_MASK; Key keycode_no_mod = p_keycode & KeyModifierMask::CODE_MASK; unsigned int xkeycode = KeyMappingX11::get_xlibcode(keycode_no_mod); - KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, 0, 0); + KeySym xkeysym = XkbKeycodeToKeysym(x11_display, xkeycode, keyboard_get_current_layout(), 0); if (is_ascii_lower_case(xkeysym)) { xkeysym -= ('a' - 'A'); } @@ -2917,7 +2931,7 @@ BitField<MouseButtonMask> DisplayServerX11::_get_mouse_button_state(MouseButton } void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo) { - WindowData wd = windows[p_window]; + WindowData &wd = windows[p_window]; // X11 functions don't know what const is XKeyEvent *xkeyevent = p_event; @@ -2963,7 +2977,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, String keysym; #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v08p) { KeySym keysym_unicode_nm = 0; // keysym used to find unicode XLookupString(&xkeyevent_no_mod, nullptr, 0, &keysym_unicode_nm, nullptr); keysym = String::chr(xkb_keysym_to_utf32(xkb_keysym_to_upper(keysym_unicode_nm))); @@ -3058,7 +3072,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, } while (status == XBufferOverflow); #endif #ifdef XKB_ENABLED - } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded) { + } else if (xkeyevent->type == KeyPress && wd.xkb_state && xkb_loaded_v05p) { xkb_compose_feed_result res = xkb_compose_state_feed(wd.xkb_state, keysym_unicode); if (res == XKB_COMPOSE_FEED_ACCEPTED) { if (xkb_compose_state_get_status(wd.xkb_state) == XKB_COMPOSE_COMPOSED) { @@ -3319,7 +3333,7 @@ Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p return p_property; } else { char *target_name = XGetAtomName(x11_display, p_target); - printf("Target '%s' not supported.\n", target_name); + print_verbose(vformat("Target '%s' not supported.", target_name)); if (target_name) { XFree(target_name); } @@ -3486,6 +3500,15 @@ void DisplayServerX11::_window_changed(XEvent *event) { wd.minimized = _window_minimize_check(window_id); wd.maximized = _window_maximize_check(window_id, "_NET_WM_STATE"); + // Readjusting the window position if the window is being reparented by the window manager for decoration + Window root, parent, *children; + unsigned int nchildren; + if (XQueryTree(x11_display, wd.x11_window, &root, &parent, &children, &nchildren) && wd.parent != parent) { + wd.parent = parent; + window_set_position(wd.position, window_id); + } + XFree(children); + { //the position in xconfigure is not useful here, obtain it manually int x = 0, y = 0; @@ -4850,7 +4873,7 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W vformat("Your video card drivers seem not to support the required Vulkan version.\n\n" "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n" "You can enable the OpenGL 3 driver by starting the engine from the\n" - "command line with the command:\n'%s --rendering-driver opengl3'\n\n" + "command line with the command:\n\n \"%s\" --rendering-driver opengl3\n\n" "If you recently updated your video card drivers, try rebooting.", executable_name), "Unable to initialize Vulkan video driver"); @@ -4873,7 +4896,9 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V #ifdef GLES3_ENABLED if (gl_manager) { - visualInfo = gl_manager->get_vi(x11_display); + Error err; + visualInfo = gl_manager->get_vi(x11_display, err); + ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't acquire visual info from display."); vi_selected = true; } #endif @@ -4968,12 +4993,13 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V { wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo.screen), win_rect.position.x, win_rect.position.y, win_rect.size.width > 0 ? win_rect.size.width : 1, win_rect.size.height > 0 ? win_rect.size.height : 1, 0, visualInfo.depth, InputOutput, visualInfo.visual, valuemask, &windowAttributes); + wd.parent = RootWindow(x11_display, visualInfo.screen); XSetWindowAttributes window_attributes_ime = {}; window_attributes_ime.event_mask = KeyPressMask | KeyReleaseMask | StructureNotifyMask | ExposureMask; wd.x11_xim_window = XCreateWindow(x11_display, wd.x11_window, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, CWEventMask, &window_attributes_ime); #ifdef XKB_ENABLED - if (dead_tbl && xkb_loaded) { + if (dead_tbl && xkb_loaded_v05p) { wd.xkb_state = xkb_compose_state_new(dead_tbl, XKB_COMPOSE_STATE_NO_FLAGS); } #endif @@ -5257,7 +5283,17 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode ERR_FAIL_MSG("Can't load XCursor dynamically."); } #ifdef XKB_ENABLED - xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0); + bool xkb_loaded = (initialize_xkbcommon(dylibloader_verbose) == 0); + xkb_loaded_v05p = xkb_loaded; + if (!xkb_context_new || !xkb_compose_table_new_from_locale || !xkb_compose_table_unref || !xkb_context_unref || !xkb_compose_state_feed || !xkb_compose_state_unref || !xkb_compose_state_new || !xkb_compose_state_get_status || !xkb_compose_state_get_utf8) { + xkb_loaded_v05p = false; + print_verbose("Detected XKBcommon library version older than 0.5, dead key composition and Unicode key labels disabled."); + } + xkb_loaded_v08p = xkb_loaded; + if (!xkb_keysym_to_utf32 || !xkb_keysym_to_upper) { + xkb_loaded_v08p = false; + print_verbose("Detected XKBcommon library version older than 0.8, Unicode key labels disabled."); + } #endif if (initialize_xext(dylibloader_verbose) != 0) { r_error = ERR_UNAVAILABLE; @@ -5312,6 +5348,15 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode r_error = OK; + { + if (!XcursorImageCreate || !XcursorImageLoadCursor || !XcursorImageDestroy || !XcursorGetDefaultSize || !XcursorGetTheme || !XcursorLibraryLoadImage) { + // There's no API to check version, check if functions are available instead. + ERR_PRINT("Unsupported Xcursor library version."); + r_error = ERR_UNAVAILABLE; + return; + } + } + for (int i = 0; i < CURSOR_MAX; i++) { cursors[i] = None; img[i] = nullptr; @@ -5328,6 +5373,71 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode return; } + { + int version_major = 0; + int version_minor = 0; + int rc = XShapeQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xshape %d.%d detected.", version_major, version_minor)); + if (rc != 1 || version_major < 1) { + ERR_PRINT("Unsupported Xshape library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XineramaQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xinerama %d.%d detected.", version_major, version_minor)); + if (rc != 1 || version_major < 1) { + ERR_PRINT("Unsupported Xinerama library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XRRQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xrandr %d.%d detected.", version_major, version_minor)); + if (rc != 1 || (version_major == 1 && version_minor < 3) || (version_major < 1)) { + ERR_PRINT("Unsupported Xrandr library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 0; + int version_minor = 0; + int rc = XRenderQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xrender %d.%d detected.", version_major, version_minor)); + if (rc != 1 || (version_major == 0 && version_minor < 11)) { + ERR_PRINT("Unsupported Xrender library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + + { + int version_major = 2; // Report 2.2 as supported by engine, but should work with 2.1 or 2.0 library as well. + int version_minor = 2; + int rc = XIQueryVersion(x11_display, &version_major, &version_minor); + print_verbose(vformat("Xinput %d.%d detected.", version_major, version_minor)); + if (rc != Success || (version_major < 2)) { + ERR_PRINT("Unsupported Xinput2 library version."); + r_error = ERR_UNAVAILABLE; + XCloseDisplay(x11_display); + return; + } + } + char *modifiers = nullptr; Bool xkb_dar = False; XAutoRepeatOn(x11_display); @@ -5750,7 +5860,7 @@ DisplayServerX11::~DisplayServerX11() { } XDestroyWindow(x11_display, wd.x11_xim_window); #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (wd.xkb_state) { xkb_compose_state_unref(wd.xkb_state); wd.xkb_state = nullptr; @@ -5762,7 +5872,7 @@ DisplayServerX11::~DisplayServerX11() { } #ifdef XKB_ENABLED - if (xkb_loaded) { + if (xkb_loaded_v05p) { if (dead_tbl) { xkb_compose_table_unref(dead_tbl); } diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h index dbe8a0ce2b..e8e0680c14 100644 --- a/platform/linuxbsd/x11/display_server_x11.h +++ b/platform/linuxbsd/x11/display_server_x11.h @@ -160,6 +160,7 @@ class DisplayServerX11 : public DisplayServer { struct WindowData { Window x11_window; Window x11_xim_window; + Window parent; ::XIC xic; bool ime_active = false; bool ime_in_progress = false; @@ -211,7 +212,8 @@ class DisplayServerX11 : public DisplayServer { String im_text; #ifdef XKB_ENABLED - bool xkb_loaded = false; + bool xkb_loaded_v05p = false; + bool xkb_loaded_v08p = false; xkb_context *xkb_ctx = nullptr; xkb_compose_table *dead_tbl = nullptr; #endif @@ -404,11 +406,13 @@ public: virtual int get_screen_count() const override; virtual int get_primary_screen() const override; + virtual int get_keyboard_focus_screen() const override; virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; virtual float screen_get_refresh_rate(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + virtual Color screen_get_pixel(const Point2i &p_position) const override; #if defined(DBUS_ENABLED) virtual void screen_set_keep_on(bool p_enable) override; diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp index 03ba95f475..ee767dfa80 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.cpp +++ b/platform/linuxbsd/x11/gl_manager_x11.cpp @@ -83,8 +83,13 @@ int GLManager_X11::_find_or_create_display(Display *p_x11_display) { d.context = memnew(GLManager_X11_Private); d.context->glx_context = nullptr; - //Error err = _create_context(d); - _create_context(d); + Error err = _create_context(d); + + if (err != OK) { + _displays.remove_at(new_display_id); + return -1; + } + return new_display_id; } @@ -191,8 +196,14 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { return OK; } -XVisualInfo GLManager_X11::get_vi(Display *p_display) { - return _displays[_find_or_create_display(p_display)].x_vi; +XVisualInfo GLManager_X11::get_vi(Display *p_display, Error &r_error) { + int display_id = _find_or_create_display(p_display); + if (display_id < 0) { + r_error = FAILED; + return XVisualInfo(); + } + r_error = OK; + return _displays[display_id].x_vi; } Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { @@ -211,6 +222,10 @@ Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window win.x11_window = p_window; win.gldisplay_id = _find_or_create_display(p_display); + if (win.gldisplay_id == -1) { + return FAILED; + } + // the display could be invalid .. check NYI GLDisplay &gl_display = _displays[win.gldisplay_id]; ::Display *x11_display = gl_display.x11_display; diff --git a/platform/linuxbsd/x11/gl_manager_x11.h b/platform/linuxbsd/x11/gl_manager_x11.h index 0eb8ab64f4..0203dff679 100644 --- a/platform/linuxbsd/x11/gl_manager_x11.h +++ b/platform/linuxbsd/x11/gl_manager_x11.h @@ -114,7 +114,7 @@ private: Error _create_context(GLDisplay &gl_display); public: - XVisualInfo get_vi(Display *p_display); + XVisualInfo get_vi(Display *p_display, Error &r_error); Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height); void window_destroy(DisplayServer::WindowID p_window_id); void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height); diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp index fe73162280..0f709872cb 100644 --- a/platform/linuxbsd/x11/key_mapping_x11.cpp +++ b/platform/linuxbsd/x11/key_mapping_x11.cpp @@ -85,8 +85,8 @@ void KeyMappingX11::initialize() { xkeysym_map[XK_Begin] = Key::CLEAR; xkeysym_map[XK_Insert] = Key::INSERT; xkeysym_map[XK_Delete] = Key::KEY_DELETE; - //xkeysym_map[XK_KP_Equal] - //xkeysym_map[XK_KP_Separator] + xkeysym_map[XK_KP_Equal] = Key::EQUAL; + xkeysym_map[XK_KP_Separator] = Key::COMMA; xkeysym_map[XK_KP_Decimal] = Key::KP_PERIOD; xkeysym_map[XK_KP_Delete] = Key::KP_PERIOD; xkeysym_map[XK_KP_Multiply] = Key::KP_MULTIPLY; @@ -220,7 +220,7 @@ void KeyMappingX11::initialize() { scancode_map[0x22] = Key::BRACKETLEFT; scancode_map[0x23] = Key::BRACKETRIGHT; scancode_map[0x24] = Key::ENTER; - scancode_map[0x25] = Key::CTRL; + scancode_map[0x25] = Key::CTRL; // Left scancode_map[0x26] = Key::A; scancode_map[0x27] = Key::S; scancode_map[0x28] = Key::D; @@ -233,7 +233,7 @@ void KeyMappingX11::initialize() { scancode_map[0x2F] = Key::SEMICOLON; scancode_map[0x30] = Key::APOSTROPHE; scancode_map[0x31] = Key::QUOTELEFT; - scancode_map[0x32] = Key::SHIFT; + scancode_map[0x32] = Key::SHIFT; // Left scancode_map[0x33] = Key::BACKSLASH; scancode_map[0x34] = Key::Z; scancode_map[0x35] = Key::X; @@ -245,9 +245,9 @@ void KeyMappingX11::initialize() { scancode_map[0x3B] = Key::COMMA; scancode_map[0x3C] = Key::PERIOD; scancode_map[0x3D] = Key::SLASH; - scancode_map[0x3E] = Key::SHIFT; + scancode_map[0x3E] = Key::SHIFT; // Right scancode_map[0x3F] = Key::KP_MULTIPLY; - scancode_map[0x40] = Key::ALT; + scancode_map[0x40] = Key::ALT; // Left scancode_map[0x41] = Key::SPACE; scancode_map[0x42] = Key::CAPSLOCK; scancode_map[0x43] = Key::F1; @@ -275,14 +275,23 @@ void KeyMappingX11::initialize() { scancode_map[0x59] = Key::KP_3; scancode_map[0x5A] = Key::KP_0; scancode_map[0x5B] = Key::KP_PERIOD; + //scancode_map[0x5C] + //scancode_map[0x5D] // Zenkaku Hankaku scancode_map[0x5E] = Key::SECTION; scancode_map[0x5F] = Key::F11; scancode_map[0x60] = Key::F12; + //scancode_map[0x61] // Romaji + //scancode_map[0x62] // Katakana + //scancode_map[0x63] // Hiragana + //scancode_map[0x64] // Henkan + //scancode_map[0x65] // Hiragana Katakana + //scancode_map[0x66] // Muhenkan + scancode_map[0x67] = Key::COMMA; // KP_Separator scancode_map[0x68] = Key::KP_ENTER; - scancode_map[0x69] = Key::CTRL; + scancode_map[0x69] = Key::CTRL; // Right scancode_map[0x6A] = Key::KP_DIVIDE; scancode_map[0x6B] = Key::PRINT; - scancode_map[0x6C] = Key::ALT; + scancode_map[0x6C] = Key::ALT; // Right scancode_map[0x6D] = Key::ENTER; scancode_map[0x6E] = Key::HOME; scancode_map[0x6F] = Key::UP; @@ -294,13 +303,28 @@ void KeyMappingX11::initialize() { scancode_map[0x75] = Key::PAGEDOWN; scancode_map[0x76] = Key::INSERT; scancode_map[0x77] = Key::KEY_DELETE; + //scancode_map[0x78] // Macro scancode_map[0x79] = Key::VOLUMEMUTE; scancode_map[0x7A] = Key::VOLUMEDOWN; scancode_map[0x7B] = Key::VOLUMEUP; + //scancode_map[0x7C] // Power + scancode_map[0x7D] = Key::EQUAL; // KP_Equal + //scancode_map[0x7E] // KP_PlusMinus scancode_map[0x7F] = Key::PAUSE; - scancode_map[0x85] = Key::META; - scancode_map[0x86] = Key::META; + scancode_map[0x80] = Key::LAUNCH0; + scancode_map[0x81] = Key::COMMA; // KP_Comma + //scancode_map[0x82] // Hangul + //scancode_map[0x83] // Hangul_Hanja + scancode_map[0x84] = Key::YEN; + scancode_map[0x85] = Key::META; // Left + scancode_map[0x86] = Key::META; // Right scancode_map[0x87] = Key::MENU; + + scancode_map[0xA6] = Key::BACK; // On Chromebooks + scancode_map[0xA7] = Key::FORWARD; // On Chromebooks + + scancode_map[0xB5] = Key::REFRESH; // On Chromebooks + scancode_map[0xBF] = Key::F13; scancode_map[0xC0] = Key::F14; scancode_map[0xC1] = Key::F15; |