summaryrefslogtreecommitdiffstats
path: root/platform/linuxbsd
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linuxbsd')
-rw-r--r--platform/linuxbsd/detect.py25
-rw-r--r--platform/linuxbsd/doc_classes/EditorExportPlatformLinuxBSD.xml73
-rw-r--r--platform/linuxbsd/export/export.cpp4
-rw-r--r--platform/linuxbsd/export/export.h1
-rw-r--r--platform/linuxbsd/export/export_plugin.cpp42
-rw-r--r--platform/linuxbsd/export/export_plugin.h5
-rw-r--r--platform/linuxbsd/freedesktop_portal_desktop.cpp11
-rw-r--r--platform/linuxbsd/freedesktop_screensaver.cpp11
-rw-r--r--platform/linuxbsd/joypad_linux.cpp8
-rw-r--r--platform/linuxbsd/os_linuxbsd.cpp147
-rw-r--r--platform/linuxbsd/tts_linux.cpp5
-rw-r--r--platform/linuxbsd/tts_linux.h2
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp274
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h6
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp23
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.h2
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.cpp44
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;