diff options
Diffstat (limited to 'platform/linuxbsd')
28 files changed, 4264 insertions, 1410 deletions
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md new file mode 100644 index 0000000000..0d3fb37be5 --- /dev/null +++ b/platform/linuxbsd/README.md @@ -0,0 +1,11 @@ +# Linux/*BSD platform port + +This folder contains the C++ code for the Linux/*BSD platform port. + +## Artwork license + +[`logo.png`](logo.png) is derived from the [Linux logo](https://isc.tamu.edu/~lewing/linux/): + +> Permission to use and/or modify this image is granted provided you acknowledge me + <lewing@isc.tamu.edu> and [The GIMP](https://isc.tamu.edu/~lewing/gimp/) + if someone asks. diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index ae75a75830..cec8706fbc 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -5,18 +5,28 @@ Import("env") from platform_methods import run_in_subprocess import platform_linuxbsd_builders -common_x11 = [ +common_linuxbsd = [ "crash_handler_linuxbsd.cpp", "os_linuxbsd.cpp", "joypad_linux.cpp", - "context_gl_x11.cpp", - "detect_prime_x11.cpp", - "display_server_x11.cpp", - "vulkan_context_x11.cpp", - "key_mapping_x11.cpp", + "freedesktop_screensaver.cpp", ] -prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_x11) +if "x11" in env and env["x11"]: + common_linuxbsd += [ + "gl_manager_x11.cpp", + "detect_prime_x11.cpp", + "display_server_x11.cpp", + "key_mapping_x11.cpp", + ] -if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: +if "vulkan" in env and env["vulkan"]: + common_linuxbsd.append("vulkan_context_x11.cpp") + +if "udev" in env and env["udev"]: + common_linuxbsd.append("libudev-so_wrap.c") + +prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_linuxbsd) + +if env["debug_symbols"] and env["separate_debug_symbols"]: env.AddPostAction(prog, run_in_subprocess(platform_linuxbsd_builders.make_debug_linuxbsd)) diff --git a/platform/linuxbsd/context_gl_x11.cpp b/platform/linuxbsd/context_gl_x11.cpp deleted file mode 100644 index 71dc9602b3..0000000000 --- a/platform/linuxbsd/context_gl_x11.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/*************************************************************************/ -/* context_gl_x11.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "context_gl_x11.h" - -#ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -#define GLX_GLXEXT_PROTOTYPES -#include <GL/glx.h> -#include <GL/glxext.h> - -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 - -typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); - -struct ContextGL_X11_Private { - ::GLXContext glx_context; -}; - -void ContextGL_X11::release_current() { - glXMakeCurrent(x11_display, None, nullptr); -} - -void ContextGL_X11::make_current() { - glXMakeCurrent(x11_display, x11_window, p->glx_context); -} - -void ContextGL_X11::swap_buffers() { - glXSwapBuffers(x11_display, x11_window); -} - -static bool ctxErrorOccurred = false; -static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) { - ctxErrorOccurred = true; - return 0; -} - -static void set_class_hint(Display *p_display, Window p_window) { - XClassHint *classHint; - - /* set the name and class hints for the window manager to use */ - classHint = XAllocClassHint(); - if (classHint) { - classHint->res_name = (char *)"Godot_Engine"; - classHint->res_class = (char *)"Godot"; - } - XSetClassHint(p_display, p_window, classHint); - XFree(classHint); -} - -Error ContextGL_X11::initialize() { - //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display)); - - GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB"); - - ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED); - - static int visual_attribs[] = { - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_DOUBLEBUFFER, true, - GLX_RED_SIZE, 1, - GLX_GREEN_SIZE, 1, - GLX_BLUE_SIZE, 1, - GLX_DEPTH_SIZE, 24, - None - }; - - static int visual_attribs_layered[] = { - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, - GLX_DOUBLEBUFFER, true, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_ALPHA_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None - }; - - int fbcount; - GLXFBConfig fbconfig = 0; - XVisualInfo *vi = nullptr; - - XSetWindowAttributes swa; - swa.event_mask = StructureNotifyMask; - swa.border_pixel = 0; - unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; - - if (OS::get_singleton()->is_layered_allowed()) { - GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount); - ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); - - for (int i = 0; i < fbcount; i++) { - vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]); - if (!vi) - continue; - - XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual); - if (!pict_format) { - XFree(vi); - vi = nullptr; - continue; - } - - fbconfig = fbc[i]; - if (pict_format->direct.alphaMask > 0) { - break; - } - } - XFree(fbc); - ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED); - - swa.background_pixmap = None; - swa.background_pixel = 0; - swa.border_pixmap = None; - valuemask |= CWBackPixel; - - } else { - GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); - ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); - - vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); - - fbconfig = fbc[0]; - XFree(fbc); - } - - int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler); - - switch (context_type) { - case GLES_2_0_COMPATIBLE: { - p->glx_context = glXCreateNewContext(x11_display, fbconfig, GLX_RGBA_TYPE, 0, true); - ERR_FAIL_COND_V(!p->glx_context, ERR_UNCONFIGURED); - } break; - } - - swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); - x11_window = XCreateWindow(x11_display, RootWindow(x11_display, vi->screen), 0, 0, OS::get_singleton()->get_video_mode().width, OS::get_singleton()->get_video_mode().height, 0, vi->depth, InputOutput, vi->visual, valuemask, &swa); - XStoreName(x11_display, x11_window, "Godot Engine"); - - ERR_FAIL_COND_V(!x11_window, ERR_UNCONFIGURED); - set_class_hint(x11_display, x11_window); - XMapWindow(x11_display, x11_window); - - XSync(x11_display, False); - XSetErrorHandler(oldHandler); - - glXMakeCurrent(x11_display, x11_window, p->glx_context); - - XFree(vi); - - return OK; -} - -int ContextGL_X11::get_window_width() { - XWindowAttributes xwa; - XGetWindowAttributes(x11_display, x11_window, &xwa); - - return xwa.width; -} - -int ContextGL_X11::get_window_height() { - XWindowAttributes xwa; - XGetWindowAttributes(x11_display, x11_window, &xwa); - - return xwa.height; -} - -void ContextGL_X11::set_use_vsync(bool p_use) { - static bool setup = false; - static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr; - static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr; - static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; - - if (!setup) { - setup = true; - String extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display)); - if (extensions.find("GLX_EXT_swap_control") != -1) - glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT"); - if (extensions.find("GLX_MESA_swap_control") != -1) - glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA"); - if (extensions.find("GLX_SGI_swap_control") != -1) - glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI"); - } - int val = p_use ? 1 : 0; - if (glXSwapIntervalMESA) { - glXSwapIntervalMESA(val); - } else if (glXSwapIntervalSGI) { - glXSwapIntervalSGI(val); - } else if (glXSwapIntervalEXT) { - GLXDrawable drawable = glXGetCurrentDrawable(); - glXSwapIntervalEXT(x11_display, drawable, val); - } else - return; - use_vsync = p_use; -} - -bool ContextGL_X11::is_using_vsync() const { - return use_vsync; -} - -ContextGL_X11::ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type) : - x11_window(p_x11_window) { - default_video_mode = p_default_video_mode; - x11_display = p_x11_display; - - context_type = p_context_type; - - double_buffer = false; - direct_render = false; - glx_minor = glx_major = 0; - p = memnew(ContextGL_X11_Private); - p->glx_context = 0; - use_vsync = false; -} - -ContextGL_X11::~ContextGL_X11() { - release_current(); - glXDestroyContext(x11_display, p->glx_context); - memdelete(p); -} - -#endif -#endif diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index e2b88b7704..9b24b24cb4 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.cpp +++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,8 +30,10 @@ #include "crash_handler_linuxbsd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" +#include "core/version.h" +#include "core/version_hash.gen.h" #include "main/main.h" #ifdef DEBUG_ENABLED @@ -61,12 +63,19 @@ static void handle_crash(int sig) { } // Dump the backtrace to stderr with a message to the user + fprintf(stderr, "\n================================================================\n"); fprintf(stderr, "%s: Program crashed with signal %d\n", __FUNCTION__, sig); if (OS::get_singleton()->get_main_loop()) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } + // Print the engine version just before, so that people are reminded to include the version in backtrace reports. + if (String(VERSION_HASH).length() != 0) { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME " (" VERSION_HASH ")\n"); + } else { + fprintf(stderr, "Engine version: " VERSION_FULL_NAME "\n"); + } fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { @@ -104,9 +113,9 @@ static void handle_crash(int sig) { // Try to get the file/line number using addr2line int ret; - Error err = OS::get_singleton()->execute(String("addr2line"), args, true, nullptr, &output, &ret); + Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret); if (err == OK) { - output.erase(output.length() - 1, 1); + output = output.substr(0, output.length() - 1); } fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data()); @@ -115,6 +124,7 @@ static void handle_crash(int sig) { free(strings); } fprintf(stderr, "-- END OF BACKTRACE --\n"); + fprintf(stderr, "================================================================\n"); // Abort to pass the error to the OS abort(); diff --git a/platform/linuxbsd/crash_handler_linuxbsd.h b/platform/linuxbsd/crash_handler_linuxbsd.h index 9bb03579bc..a3dae0cc22 100644 --- a/platform/linuxbsd/crash_handler_linuxbsd.h +++ b/platform/linuxbsd/crash_handler_linuxbsd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index f5e2c72bbc..07e16a982b 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -12,47 +12,48 @@ def get_name(): def can_build(): - if os.name != "posix" or sys.platform == "darwin": return False # Check the minimal dependencies x11_error = os.system("pkg-config --version > /dev/null") if x11_error: + print("Error: pkg-config not found. Aborting.") return False - x11_error = os.system("pkg-config x11 --modversion > /dev/null ") + x11_error = os.system("pkg-config x11 --modversion > /dev/null") if x11_error: + print("Error: X11 libraries not found. Aborting.") return False - x11_error = os.system("pkg-config xcursor --modversion > /dev/null ") + x11_error = os.system("pkg-config xcursor --modversion > /dev/null") if x11_error: - print("xcursor not found.. x11 disabled.") + print("Error: Xcursor library not found. Aborting.") return False - x11_error = os.system("pkg-config xinerama --modversion > /dev/null ") + x11_error = os.system("pkg-config xinerama --modversion > /dev/null") if x11_error: - print("xinerama not found.. x11 disabled.") + print("Error: Xinerama library not found. Aborting.") return False - x11_error = os.system("pkg-config xext --modversion > /dev/null ") + x11_error = os.system("pkg-config xext --modversion > /dev/null") if x11_error: - print("xext not found.. x11 disabled.") + print("Error: Xext library not found. Aborting.") return False - x11_error = os.system("pkg-config xrandr --modversion > /dev/null ") + x11_error = os.system("pkg-config xrandr --modversion > /dev/null") if x11_error: - print("xrandr not found.. x11 disabled.") + print("Error: XrandR library not found. Aborting.") return False - x11_error = os.system("pkg-config xrender --modversion > /dev/null ") + x11_error = os.system("pkg-config xrender --modversion > /dev/null") if x11_error: - print("xrender not found.. x11 disabled.") + print("Error: XRender library not found. Aborting.") return False - x11_error = os.system("pkg-config xi --modversion > /dev/null ") + x11_error = os.system("pkg-config xi --modversion > /dev/null") if x11_error: - print("xi not found.. Aborting.") + print("Error: Xi library not found. Aborting.") return False return True @@ -65,15 +66,18 @@ def get_opts(): BoolVariable("use_llvm", "Use the LLVM compiler", False), BoolVariable("use_lld", "Use the LLD linker", False), BoolVariable("use_thinlto", "Use ThinLTO", False), - BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", False), + BoolVariable("use_static_cpp", "Link libgcc and libstdc++ statically for better portability", True), BoolVariable("use_coverage", "Test Godot coverage", False), BoolVariable("use_ubsan", "Use LLVM/GCC compiler undefined behavior sanitizer (UBSAN)", False), - BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN))", False), - BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN))", False), - BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN))", False), + BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False), + BoolVariable("use_lsan", "Use LLVM/GCC compiler leak sanitizer (LSAN)", False), + BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False), + BoolVariable("use_msan", "Use LLVM compiler memory sanitizer (MSAN)", False), BoolVariable("pulseaudio", "Detect and use PulseAudio", True), - BoolVariable("udev", "Use udev for gamepad connection callbacks", False), - EnumVariable("debug_symbols", "Add debugging symbols to release builds", "yes", ("yes", "no", "full")), + BoolVariable("dbus", "Detect and use D-Bus to handle screensaver", True), + BoolVariable("udev", "Use udev for gamepad connection callbacks", True), + BoolVariable("x11", "Enable X11 display", True), + BoolVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", True), BoolVariable("separate_debug_symbols", "Create a separate file containing debugging symbols", False), BoolVariable("touch", "Enable touch events", True), BoolVariable("execinfo", "Use libexecinfo on systems where glibc is not available", False), @@ -81,40 +85,32 @@ def get_opts(): def get_flags(): - return [] def configure(env): - ## Build type if env["target"] == "release": if env["optimize"] == "speed": # optimize for speed (default) env.Prepend(CCFLAGS=["-O3"]) - else: # optimize for size + elif env["optimize"] == "size": # optimize for size env.Prepend(CCFLAGS=["-Os"]) - if env["debug_symbols"] == "yes": - env.Prepend(CCFLAGS=["-g1"]) - if env["debug_symbols"] == "full": + if env["debug_symbols"]: env.Prepend(CCFLAGS=["-g2"]) elif env["target"] == "release_debug": if env["optimize"] == "speed": # optimize for speed (default) env.Prepend(CCFLAGS=["-O2"]) - else: # optimize for size + elif env["optimize"] == "size": # optimize for size env.Prepend(CCFLAGS=["-Os"]) - env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) - if env["debug_symbols"] == "yes": - env.Prepend(CCFLAGS=["-g1"]) - if env["debug_symbols"] == "full": + if env["debug_symbols"]: env.Prepend(CCFLAGS=["-g2"]) elif env["target"] == "debug": env.Prepend(CCFLAGS=["-g3"]) - env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(LINKFLAGS=["-rdynamic"]) ## Architecture @@ -123,6 +119,21 @@ def configure(env): if env["bits"] == "default": env["bits"] = "64" if is64 else "32" + machines = { + "riscv64": "rv64", + "ppc64le": "ppc64", + "ppc64": "ppc64", + "ppcle": "ppc", + "ppc": "ppc", + } + + if env["arch"] == "" and platform.machine() in machines: + env["arch"] = machines[platform.machine()] + + if env["arch"] == "rv64": + # G = General-purpose extensions, C = Compression extension (very common). + env.Append(CCFLAGS=["-march=rv64gc"]) + ## Compiler configuration if "CXX" in env and "clang" in os.path.basename(env["CXX"]): @@ -133,8 +144,6 @@ def configure(env): if "clang++" not in os.path.basename(env["CXX"]): env["CC"] = "clang" env["CXX"] = "clang++" - env["LINK"] = "clang++" - env.Append(CPPDEFINES=["TYPED_METHOD_BIND"]) env.extra_suffix = ".llvm" + env.extra_suffix if env["use_lld"]: @@ -144,22 +153,34 @@ def configure(env): # A convenience so you don't need to write use_lto too when using SCons env["use_lto"] = True else: - print("Using LLD with GCC is not supported yet, try compiling with 'use_llvm=yes'.") + print("Using LLD with GCC is not supported yet. Try compiling with 'use_llvm=yes'.") sys.exit(255) if env["use_coverage"]: env.Append(CCFLAGS=["-ftest-coverage", "-fprofile-arcs"]) env.Append(LINKFLAGS=["-ftest-coverage", "-fprofile-arcs"]) - if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"]: + if env["use_ubsan"] or env["use_asan"] or env["use_lsan"] or env["use_tsan"] or env["use_msan"]: env.extra_suffix += "s" if env["use_ubsan"]: - env.Append(CCFLAGS=["-fsanitize=undefined"]) + env.Append( + CCFLAGS=[ + "-fsanitize=undefined,shift,shift-exponent,integer-divide-by-zero,unreachable,vla-bound,null,return,signed-integer-overflow,bounds,float-divide-by-zero,float-cast-overflow,nonnull-attribute,returns-nonnull-attribute,bool,enum,vptr,pointer-overflow,builtin" + ] + ) env.Append(LINKFLAGS=["-fsanitize=undefined"]) + if env["use_llvm"]: + env.Append( + CCFLAGS=[ + "-fsanitize=nullability-return,nullability-arg,function,nullability-assign,implicit-integer-sign-change" + ] + ) + else: + env.Append(CCFLAGS=["-fsanitize=bounds-strict"]) if env["use_asan"]: - env.Append(CCFLAGS=["-fsanitize=address"]) + env.Append(CCFLAGS=["-fsanitize=address,pointer-subtract,pointer-compare"]) env.Append(LINKFLAGS=["-fsanitize=address"]) if env["use_lsan"]: @@ -170,6 +191,12 @@ def configure(env): env.Append(CCFLAGS=["-fsanitize=thread"]) env.Append(LINKFLAGS=["-fsanitize=thread"]) + if env["use_msan"] and env["use_llvm"]: + env.Append(CCFLAGS=["-fsanitize=memory"]) + env.Append(CCFLAGS=["-fsanitize-memory-track-origins"]) + env.Append(CCFLAGS=["-fsanitize-recover=memory"]) + env.Append(LINKFLAGS=["-fsanitize=memory"]) + if env["use_lto"]: if not env["use_llvm"] and env.GetOption("num_jobs") > 1: env.Append(CCFLAGS=["-flto"]) @@ -189,11 +216,6 @@ def configure(env): env.Append(CCFLAGS=["-pipe"]) env.Append(LINKFLAGS=["-pipe"]) - # -fpie and -no-pie is supported on GCC 6+ and Clang 4+, both below our - # minimal requirements. - env.Append(CCFLAGS=["-fpie"]) - env.Append(LINKFLAGS=["-no-pie"]) - ## Dependencies env.ParseConfig("pkg-config x11 --cflags --libs") @@ -211,14 +233,31 @@ def configure(env): # freetype depends on libpng and zlib, so bundling one of them while keeping others # as shared libraries leads to weird issues - if env["builtin_freetype"] or env["builtin_libpng"] or env["builtin_zlib"]: + if ( + env["builtin_freetype"] + or env["builtin_libpng"] + or env["builtin_zlib"] + or env["builtin_graphite"] + or env["builtin_harfbuzz"] + ): env["builtin_freetype"] = True env["builtin_libpng"] = True env["builtin_zlib"] = True + env["builtin_graphite"] = True + env["builtin_harfbuzz"] = True if not env["builtin_freetype"]: env.ParseConfig("pkg-config freetype2 --cflags --libs") + if not env["builtin_graphite"]: + env.ParseConfig("pkg-config graphite2 --cflags --libs") + + if not env["builtin_icu"]: + env.ParseConfig("pkg-config icu-uc --cflags --libs") + + if not env["builtin_harfbuzz"]: + env.ParseConfig("pkg-config harfbuzz harfbuzz-icu --cflags --libs") + if not env["builtin_libpng"]: env.ParseConfig("pkg-config libpng16 --cflags --libs") @@ -264,17 +303,10 @@ def configure(env): if any(platform.machine() in s for s in list_of_x86): env["x86_libtheora_opt_gcc"] = True - if not env["builtin_libvpx"]: - env.ParseConfig("pkg-config vpx --cflags --libs") - if not env["builtin_libvorbis"]: env["builtin_libogg"] = False # Needed to link against system libvorbis env.ParseConfig("pkg-config vorbis vorbisfile --cflags --libs") - if not env["builtin_opus"]: - env["builtin_libogg"] = False # Needed to link against system opus - env.ParseConfig("pkg-config opus opusfile --cflags --libs") - if not env["builtin_libogg"]: env.ParseConfig("pkg-config ogg --cflags --libs") @@ -298,50 +330,66 @@ def configure(env): if not env["builtin_pcre2"]: env.ParseConfig("pkg-config libpcre2-32 --cflags --libs") + if not env["builtin_embree"]: + # No pkgconfig file so far, hardcode expected lib name. + env.Append(LIBS=["embree3"]) + ## Flags if os.system("pkg-config --exists alsa") == 0: # 0 means found - print("Enabling ALSA") + env["alsa"] = True env.Append(CPPDEFINES=["ALSA_ENABLED", "ALSAMIDI_ENABLED"]) - # Don't parse --cflags, we don't need to add /usr/include/alsa to include path - env.ParseConfig("pkg-config alsa --libs") else: - print("ALSA libraries not found, disabling driver") + print("Warning: ALSA libraries not found. Disabling the ALSA audio driver.") if env["pulseaudio"]: if os.system("pkg-config --exists libpulse") == 0: # 0 means found - print("Enabling PulseAudio") env.Append(CPPDEFINES=["PULSEAUDIO_ENABLED"]) - env.ParseConfig("pkg-config --cflags --libs libpulse") + env.ParseConfig("pkg-config --cflags libpulse") else: - print("PulseAudio development libraries not found, disabling driver") + print("Warning: PulseAudio development libraries not found. Disabling the PulseAudio audio driver.") + + if env["dbus"]: + if os.system("pkg-config --exists dbus-1") == 0: # 0 means found + env.Append(CPPDEFINES=["DBUS_ENABLED"]) + env.ParseConfig("pkg-config --cflags --libs dbus-1") + else: + print("Warning: D-Bus development libraries not found. Disabling screensaver prevention.") if platform.system() == "Linux": env.Append(CPPDEFINES=["JOYDEV_ENABLED"]) - if env["udev"]: if os.system("pkg-config --exists libudev") == 0: # 0 means found - print("Enabling udev support") env.Append(CPPDEFINES=["UDEV_ENABLED"]) - env.ParseConfig("pkg-config libudev --cflags --libs") else: - print("libudev development libraries not found, disabling udev support") + print("Warning: libudev development libraries not found. Disabling controller hotplugging support.") + else: + env["udev"] = False # Linux specific # Linkflags below this line should typically stay the last ones if not env["builtin_zlib"]: env.ParseConfig("pkg-config zlib --cflags --libs") env.Prepend(CPPPATH=["#platform/linuxbsd"]) - env.Append(CPPDEFINES=["X11_ENABLED", "UNIX_ENABLED"]) - env.Append(CPPDEFINES=["VULKAN_ENABLED"]) - if not env["builtin_vulkan"]: - env.ParseConfig("pkg-config vulkan --cflags --libs") - if not env["builtin_glslang"]: - # No pkgconfig file for glslang so far - env.Append(LIBS=["glslang", "SPIRV"]) + if env["x11"]: + if not env["vulkan"]: + print("Error: X11 support requires vulkan=yes") + env.Exit(255) + env.Append(CPPDEFINES=["X11_ENABLED"]) - # env.Append(CPPDEFINES=['OPENGL_ENABLED']) + env.Append(CPPDEFINES=["UNIX_ENABLED"]) + env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)]) + + if env["vulkan"]: + env.Append(CPPDEFINES=["VULKAN_ENABLED"]) + if not env["use_volk"]: + env.ParseConfig("pkg-config vulkan --cflags --libs") + if not env["builtin_glslang"]: + # No pkgconfig file for glslang so far + env.Append(LIBS=["glslang", "SPIRV"]) + + env.Append(CPPDEFINES=["GLES3_ENABLED"]) env.Append(LIBS=["GL"]) env.Append(LIBS=["pthread"]) @@ -363,7 +411,7 @@ def configure(env): gnu_ld_version = re.search("^GNU ld [^$]*(\d+\.\d+)$", linker_version_str, re.MULTILINE) if not gnu_ld_version: print( - "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld" + "Warning: Creating template binaries enabled for PCK embedding is currently only supported with GNU ld, not gold or LLD." ) else: if float(gnu_ld_version.group(1)) >= 2.30: @@ -383,3 +431,9 @@ def configure(env): # Link those statically for portability if env["use_static_cpp"]: env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) + if env["use_llvm"]: + env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a" + + else: + if env["use_llvm"]: + env.Append(LIBS=["atomic"]) diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp index 1e46d3222d..c775546f15 100644 --- a/platform/linuxbsd/detect_prime_x11.cpp +++ b/platform/linuxbsd/detect_prime_x11.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,12 +29,12 @@ /*************************************************************************/ #ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) -#include "detect_prime.h" +#include "detect_prime_x11.h" -#include "core/print_string.h" -#include "core/ustring.h" +#include "core/string/print_string.h" +#include "core/string/ustring.h" #include <stdlib.h> @@ -56,11 +56,12 @@ typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLX struct vendor { const char *glxvendor; - int priority; + int priority = 0; }; vendor vendormap[] = { { "Advanced Micro Devices, Inc.", 30 }, + { "AMD", 30 }, { "NVIDIA Corporation", 30 }, { "X.Org", 30 }, { "Intel Open Source Technology Center", 20 }, @@ -128,7 +129,7 @@ void create_context() { int detect_prime() { pid_t p; - int priorities[2]; + int priorities[2] = {}; String vendors[2]; String renderers[2]; diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index 039bdee76b..88d00b3acd 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,7 +29,7 @@ /*************************************************************************/ #ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) int detect_prime(); diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index e3cf992302..2a62780410 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,17 +32,23 @@ #ifdef X11_ENABLED -#include "core/print_string.h" -#include "core/project_settings.h" +#include "core/config/project_settings.h" +#include "core/string/print_string.h" +#include "core/string/ustring.h" #include "detect_prime_x11.h" #include "key_mapping_x11.h" #include "main/main.h" #include "scene/resources/texture.h" #if defined(VULKAN_ENABLED) -#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" +#endif + +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -94,6 +100,15 @@ static const double abs_resolution_mult = 10000.0; static const double abs_resolution_range_mult = 10.0; +// Hints for X11 fullscreen +struct Hints { + unsigned long flags = 0; + unsigned long functions = 0; + unsigned long decorations = 0; + long inputMode = 0; + unsigned long status = 0; +}; + bool DisplayServerX11::has_feature(Feature p_feature) const { switch (p_feature) { case FEATURE_SUBWINDOWS: @@ -111,6 +126,10 @@ bool DisplayServerX11::has_feature(Feature p_feature) const { case FEATURE_ICON: case FEATURE_NATIVE_ICON: case FEATURE_SWAP_BUFFERS: +#ifdef DBUS_ENABLED + case FEATURE_KEEP_SCREEN_ON: +#endif + case FEATURE_CLIPBOARD_PRIMARY: return true; default: { } @@ -123,70 +142,6 @@ String DisplayServerX11::get_name() const { return "X11"; } -void DisplayServerX11::alert(const String &p_alert, const String &p_title) { - const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; - - String path = OS::get_singleton()->get_environment("PATH"); - Vector<String> path_elems = path.split(":", false); - String program; - - for (int i = 0; i < path_elems.size(); i++) { - for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { - String tested_path = path_elems[i].plus_file(message_programs[k]); - - if (FileAccess::exists(tested_path)) { - program = tested_path; - break; - } - } - - if (program.length()) { - break; - } - } - - List<String> args; - - if (program.ends_with("zenity")) { - args.push_back("--error"); - args.push_back("--width"); - args.push_back("500"); - args.push_back("--title"); - args.push_back(p_title); - args.push_back("--text"); - args.push_back(p_alert); - } - - if (program.ends_with("kdialog")) { - args.push_back("--error"); - args.push_back(p_alert); - args.push_back("--title"); - args.push_back(p_title); - } - - if (program.ends_with("Xdialog")) { - args.push_back("--title"); - args.push_back(p_title); - args.push_back("--msgbox"); - args.push_back(p_alert); - args.push_back("0"); - args.push_back("0"); - } - - if (program.ends_with("xmessage")) { - args.push_back("-center"); - args.push_back("-title"); - args.push_back(p_title); - args.push_back(p_alert); - } - - if (program.length()) { - OS::get_singleton()->execute(program, args, true); - } else { - print_line(p_alert); - } -} - void DisplayServerX11::_update_real_mouse_position(const WindowData &wd) { Window root_return, child_return; int root_x, root_y, win_x, win_y; @@ -322,23 +277,19 @@ bool DisplayServerX11::_refresh_device_info() { } void DisplayServerX11::_flush_mouse_motion() { - while (true) { - if (XPending(x11_display) > 0) { - XEvent event; - XPeekEvent(x11_display, &event); - - if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { - XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; - - if (event_data->evtype == XI_RawMotion) { - XNextEvent(x11_display, &event); - } else { - break; - } - } else { - break; + // Block events polling while flushing motion events. + MutexLock mutex_lock(events_mutex); + + for (uint32_t event_index = 0; event_index < polled_events.size(); ++event_index) { + XEvent &event = polled_events[event_index]; + if (XGetEventData(x11_display, &event.xcookie) && event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { + XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; + if (event_data->evtype == XI_RawMotion) { + XFreeEventData(x11_display, &event.xcookie); + polled_events.remove(event_index--); + continue; } - } else { + XFreeEventData(x11_display, &event.xcookie); break; } } @@ -354,23 +305,23 @@ void DisplayServerX11::mouse_set_mode(MouseMode p_mode) { return; } - if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) { + if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { XUngrabPointer(x11_display, CurrentTime); } // The only modes that show a cursor are VISIBLE and CONFINED bool showCursor = (p_mode == MOUSE_MODE_VISIBLE || p_mode == MOUSE_MODE_CONFINED); - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { + for (const KeyValue<WindowID, WindowData> &E : windows) { if (showCursor) { - XDefineCursor(x11_display, E->get().x11_window, cursors[current_cursor]); // show cursor + XDefineCursor(x11_display, E.value.x11_window, cursors[current_cursor]); // show cursor } else { - XDefineCursor(x11_display, E->get().x11_window, null_cursor); // hide cursor + XDefineCursor(x11_display, E.value.x11_window, null_cursor); // hide cursor } } mouse_mode = p_mode; - if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED) { + if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { //flush pending motion events _flush_mouse_motion(); WindowData &main_window = windows[MAIN_WINDOW_ID]; @@ -444,67 +395,182 @@ Point2i DisplayServerX11::mouse_get_absolute_position() const { return Vector2i(); } -int DisplayServerX11::mouse_get_button_state() const { +MouseButton DisplayServerX11::mouse_get_button_state() const { return last_button_state; } void DisplayServerX11::clipboard_set(const String &p_text) { _THREAD_SAFE_METHOD_ - internal_clipboard = p_text; + { + // The clipboard content can be accessed while polling for events. + MutexLock mutex_lock(events_mutex); + internal_clipboard = p_text; + } + XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime); XSetSelectionOwner(x11_display, XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime); } -static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard, Atom target) { +void DisplayServerX11::clipboard_set_primary(const String &p_text) { + _THREAD_SAFE_METHOD_ + if (!p_text.is_empty()) { + { + // The clipboard content can be accessed while polling for events. + MutexLock mutex_lock(events_mutex); + internal_clipboard_primary = p_text; + } + + XSetSelectionOwner(x11_display, XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, CurrentTime); + XSetSelectionOwner(x11_display, XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window, CurrentTime); + } +} + +Bool DisplayServerX11::_predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg) { + if (event->type == SelectionNotify && event->xselection.requestor == *(Window *)arg) { + return True; + } else { + return False; + } +} + +Bool DisplayServerX11::_predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg) { + if (event->type == PropertyNotify && event->xproperty.state == PropertyNewValue) { + return True; + } else { + return False; + } +} + +String DisplayServerX11::_clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const { String ret; - Atom type; - Atom selection = XA_PRIMARY; - int format, result; - unsigned long len, bytes_left, dummy; - unsigned char *data; - Window Sown = XGetSelectionOwner(x11_display, p_source); - - if (Sown == x11_window) { - return p_internal_clipboard; - }; + Window selection_owner = XGetSelectionOwner(x11_display, p_source); + if (selection_owner == x11_window) { + static const char *target_type = "PRIMARY"; + if (p_source != None && String(XGetAtomName(x11_display, p_source)) == target_type) { + return internal_clipboard_primary; + } else { + return internal_clipboard; + } + } + + if (selection_owner != None) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); - if (Sown != None) { + Atom selection = XA_PRIMARY; XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); + XFlush(x11_display); - while (true) { - XEvent event; - XNextEvent(x11_display, &event); - if (event.type == SelectionNotify && event.xselection.requestor == x11_window) { - break; - }; - }; - // - // Do not get any data, see how much data is there - // + // Blocking wait for predicate to be True and remove the event from the queue. + XEvent event; + XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window); + + // Do not get any data, see how much data is there. + Atom type; + int format, result; + unsigned long len, bytes_left, dummy; + unsigned char *data; XGetWindowProperty(x11_display, x11_window, selection, // Tricky.. 0, 0, // offset - len 0, // Delete 0==FALSE - AnyPropertyType, //flag + AnyPropertyType, // flag &type, // return type &format, // return format - &len, &bytes_left, //that + &len, &bytes_left, // data length &data); - // DATA is There - if (bytes_left > 0) { + + if (data) { + XFree(data); + } + + if (type == XInternAtom(x11_display, "INCR", 0)) { + // Data is going to be received incrementally. + DEBUG_LOG_X11("INCR selection started.\n"); + + LocalVector<uint8_t> incr_data; + uint32_t data_size = 0; + bool success = false; + + // Delete INCR property to notify the owner. + XDeleteProperty(x11_display, x11_window, type); + + // Process events from the queue. + bool done = false; + while (!done) { + if (!_wait_for_events()) { + // Error or timeout, abort. + break; + } + + // Non-blocking wait for next event and remove it from the queue. + XEvent ev; + while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_incr, nullptr)) { + result = XGetWindowProperty(x11_display, x11_window, + selection, // selection type + 0, LONG_MAX, // offset - len + True, // delete property to notify the owner + AnyPropertyType, // flag + &type, // return type + &format, // return format + &len, &bytes_left, // data length + &data); + + DEBUG_LOG_X11("PropertyNotify: len=%lu, format=%i\n", len, format); + + if (result == Success) { + if (data && (len > 0)) { + uint32_t prev_size = incr_data.size(); + if (prev_size == 0) { + // First property contains initial data size. + unsigned long initial_size = *(unsigned long *)data; + incr_data.resize(initial_size); + } else { + // New chunk, resize to be safe and append data. + incr_data.resize(MAX(data_size + len, prev_size)); + memcpy(incr_data.ptr() + data_size, data, len); + data_size += len; + } + } else { + // Last chunk, process finished. + done = true; + success = true; + } + } else { + printf("Failed to get selection data chunk.\n"); + done = true; + } + + if (data) { + XFree(data); + } + + if (done) { + break; + } + } + } + + if (success && (data_size > 0)) { + ret.parse_utf8((const char *)incr_data.ptr(), data_size); + } + } else if (bytes_left > 0) { + // Data is ready and can be processed all at once. result = XGetWindowProperty(x11_display, x11_window, selection, 0, bytes_left, 0, AnyPropertyType, &type, &format, &len, &dummy, &data); + if (result == Success) { ret.parse_utf8((const char *)data); } else { - printf("FAIL\n"); + printf("Failed to get selection data.\n"); } + if (data) { XFree(data); } @@ -514,14 +580,14 @@ static String _clipboard_get_impl(Atom p_source, Window x11_window, ::Display *x return ret; } -static String _clipboard_get(Atom p_source, Window x11_window, ::Display *x11_display, String p_internal_clipboard) { +String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const { String ret; Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True); if (utf8_atom != None) { - ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, utf8_atom); + ret = _clipboard_get_impl(p_source, x11_window, utf8_atom); } - if (ret == "") { - ret = _clipboard_get_impl(p_source, x11_window, x11_display, p_internal_clipboard, XA_STRING); + if (ret.is_empty()) { + ret = _clipboard_get_impl(p_source, x11_window, XA_STRING); } return ret; } @@ -530,15 +596,82 @@ String DisplayServerX11::clipboard_get() const { _THREAD_SAFE_METHOD_ String ret; - ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard); + ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window); - if (ret == "") { - ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window, x11_display, internal_clipboard); - }; + if (ret.is_empty()) { + ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window); + } + + return ret; +} + +String DisplayServerX11::clipboard_get_primary() const { + _THREAD_SAFE_METHOD_ + + String ret; + ret = _clipboard_get(XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window); + + if (ret.is_empty()) { + ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window); + } return ret; } +Bool DisplayServerX11::_predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg) { + if (event->xany.window == *(Window *)arg) { + return (event->type == SelectionRequest) || + (event->type == SelectionNotify); + } else { + return False; + } +} + +void DisplayServerX11::_clipboard_transfer_ownership(Atom p_source, Window x11_window) const { + _THREAD_SAFE_METHOD_ + + Window selection_owner = XGetSelectionOwner(x11_display, p_source); + + if (selection_owner != x11_window) { + return; + } + + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + Atom clipboard_manager = XInternAtom(x11_display, "CLIPBOARD_MANAGER", False); + Atom save_targets = XInternAtom(x11_display, "SAVE_TARGETS", False); + XConvertSelection(x11_display, clipboard_manager, save_targets, None, + x11_window, CurrentTime); + + // Process events from the queue. + while (true) { + if (!_wait_for_events()) { + // Error or timeout, abort. + break; + } + + // Non-blocking wait for next event and remove it from the queue. + XEvent ev; + while (XCheckIfEvent(x11_display, &ev, _predicate_clipboard_save_targets, (XPointer)&x11_window)) { + switch (ev.type) { + case SelectionRequest: + _handle_selection_request_event(&(ev.xselectionrequest)); + break; + + case SelectionNotify: { + if (ev.xselection.target == save_targets) { + // Once SelectionNotify is received, we're done whether it succeeded or not. + return; + } + + break; + } + } + } + } +} + int DisplayServerX11::get_screen_count() const { _THREAD_SAFE_METHOD_ @@ -555,35 +688,59 @@ int DisplayServerX11::get_screen_count() const { return count; } -Point2i DisplayServerX11::screen_get_position(int p_screen) const { - _THREAD_SAFE_METHOD_ +Rect2i DisplayServerX11::_screen_get_rect(int p_screen) const { + Rect2i rect(0, 0, 0, 0); if (p_screen == SCREEN_OF_MAIN_WINDOW) { p_screen = window_get_current_screen(); } - // Using Xinerama Extension + ERR_FAIL_COND_V(p_screen < 0, rect); + + // Using Xinerama Extension. int event_base, error_base; - const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); - if (!ext_okay) { - return Point2i(0, 0); - } + if (XineramaQueryExtension(x11_display, &event_base, &error_base)) { + int count; + XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); + + // Check if screen is valid. + if (p_screen < count) { + rect.position.x = xsi[p_screen].x_org; + rect.position.y = xsi[p_screen].y_org; + rect.size.width = xsi[p_screen].width; + rect.size.height = xsi[p_screen].height; + } else { + ERR_PRINT("Invalid screen index: " + itos(p_screen) + "(count: " + itos(count) + ")."); + } - int count; - XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); - if (p_screen >= count) { - return Point2i(0, 0); + if (xsi) { + XFree(xsi); + } } - Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org); + return rect; +} - XFree(xsi); +Point2i DisplayServerX11::screen_get_position(int p_screen) const { + _THREAD_SAFE_METHOD_ - return position; + return _screen_get_rect(p_screen).position; } Size2i DisplayServerX11::screen_get_size(int p_screen) const { - return screen_get_usable_rect(p_screen).size; + _THREAD_SAFE_METHOD_ + + return _screen_get_rect(p_screen).size; +} + +bool g_bad_window = false; +int bad_window_error_handler(Display *display, XErrorEvent *error) { + if (error->error_code == BadWindow) { + g_bad_window = true; + } else { + ERR_PRINT("Unhandled XServer error code: " + itos(error->error_code)); + } + return 0; } Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { @@ -593,21 +750,276 @@ Rect2i DisplayServerX11::screen_get_usable_rect(int p_screen) const { p_screen = window_get_current_screen(); } - // Using Xinerama Extension - int event_base, error_base; - const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base); - if (!ext_okay) { - return Rect2i(0, 0, 0, 0); + int screen_count = get_screen_count(); + + // Check if screen is valid. + ERR_FAIL_INDEX_V(p_screen, screen_count, Rect2i(0, 0, 0, 0)); + + bool is_multiscreen = screen_count > 1; + + // Use full monitor size as fallback. + Rect2i rect = _screen_get_rect(p_screen); + + // There's generally only one screen reported by xlib even in multi-screen setup, + // in this case it's just one virtual screen composed of all physical monitors. + int x11_screen_count = ScreenCount(x11_display); + Window x11_window = RootWindow(x11_display, p_screen < x11_screen_count ? p_screen : 0); + + Atom type; + int format = 0; + unsigned long remaining = 0; + + // Find active desktop for the root window. + unsigned int desktop_index = 0; + Atom desktop_prop = XInternAtom(x11_display, "_NET_CURRENT_DESKTOP", True); + if (desktop_prop != None) { + unsigned long desktop_len = 0; + unsigned char *desktop_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &desktop_len, &remaining, &desktop_data) == Success) { + if ((format == 32) && (desktop_len > 0) && desktop_data) { + desktop_index = (unsigned int)desktop_data[0]; + } + if (desktop_data) { + XFree(desktop_data); + } + } } - int count; - XineramaScreenInfo *xsi = XineramaQueryScreens(x11_display, &count); - if (p_screen >= count) { - return Rect2i(0, 0, 0, 0); + bool use_simple_method = true; + + // First check for GTK work area, which is more accurate for multi-screen setup. + if (is_multiscreen) { + // Use already calculated work area when available. + Atom gtk_workareas_prop = XInternAtom(x11_display, "_GTK_WORKAREAS", False); + if (gtk_workareas_prop != None) { + char gtk_workarea_prop_name[32]; + snprintf(gtk_workarea_prop_name, 32, "_GTK_WORKAREAS_D%d", desktop_index); + Atom gtk_workarea_prop = XInternAtom(x11_display, gtk_workarea_prop_name, True); + if (gtk_workarea_prop != None) { + unsigned long workarea_len = 0; + unsigned char *workarea_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, gtk_workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) { + if ((format == 32) && (workarea_len % 4 == 0) && workarea_data) { + long *rect_data = (long *)workarea_data; + for (uint32_t data_offset = 0; data_offset < workarea_len; data_offset += 4) { + Rect2i workarea_rect; + workarea_rect.position.x = rect_data[data_offset]; + workarea_rect.position.y = rect_data[data_offset + 1]; + workarea_rect.size.x = rect_data[data_offset + 2]; + workarea_rect.size.y = rect_data[data_offset + 3]; + + // Intersect with actual monitor size to find the correct area, + // because areas are not in the same order as screens from Xinerama. + if (rect.grow(-1).intersects(workarea_rect)) { + rect = rect.intersection(workarea_rect); + XFree(workarea_data); + return rect; + } + } + } + } + if (workarea_data) { + XFree(workarea_data); + } + } + } + + // Fallback to calculating work area by hand from struts. + Atom client_list_prop = XInternAtom(x11_display, "_NET_CLIENT_LIST", True); + if (client_list_prop != None) { + unsigned long clients_len = 0; + unsigned char *clients_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, client_list_prop, 0, LONG_MAX, False, XA_WINDOW, &type, &format, &clients_len, &remaining, &clients_data) == Success) { + if ((format == 32) && (clients_len > 0) && clients_data) { + Window *windows_data = (Window *)clients_data; + + Rect2i desktop_rect; + bool desktop_valid = false; + + // Get full desktop size. + { + Atom desktop_geometry_prop = XInternAtom(x11_display, "_NET_DESKTOP_GEOMETRY", True); + if (desktop_geometry_prop != None) { + unsigned long geom_len = 0; + unsigned char *geom_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_geometry_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &geom_len, &remaining, &geom_data) == Success) { + if ((format == 32) && (geom_len >= 2) && geom_data) { + desktop_valid = true; + long *size_data = (long *)geom_data; + desktop_rect.size.x = size_data[0]; + desktop_rect.size.y = size_data[1]; + } + } + if (geom_data) { + XFree(geom_data); + } + } + } + + // Get full desktop position. + if (desktop_valid) { + Atom desktop_viewport_prop = XInternAtom(x11_display, "_NET_DESKTOP_VIEWPORT", True); + if (desktop_viewport_prop != None) { + unsigned long viewport_len = 0; + unsigned char *viewport_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, desktop_viewport_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &viewport_len, &remaining, &viewport_data) == Success) { + if ((format == 32) && (viewport_len >= 2) && viewport_data) { + desktop_valid = true; + long *pos_data = (long *)viewport_data; + desktop_rect.position.x = pos_data[0]; + desktop_rect.position.y = pos_data[1]; + } + } + if (viewport_data) { + XFree(viewport_data); + } + } + } + + if (desktop_valid) { + use_simple_method = false; + + // Handle bad window errors silently because there's no other way to check + // that one of the windows has been destroyed in the meantime. + int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&bad_window_error_handler); + + for (unsigned long win_index = 0; win_index < clients_len; ++win_index) { + g_bad_window = false; + + // Remove strut size from desktop size to get a more accurate result. + bool strut_found = false; + unsigned long strut_len = 0; + unsigned char *strut_data = nullptr; + Atom strut_partial_prop = XInternAtom(x11_display, "_NET_WM_STRUT_PARTIAL", True); + if (strut_partial_prop != None) { + if (XGetWindowProperty(x11_display, windows_data[win_index], strut_partial_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) { + strut_found = true; + } + } + // Fallback to older strut property. + if (!g_bad_window && !strut_found) { + Atom strut_prop = XInternAtom(x11_display, "_NET_WM_STRUT", True); + if (strut_prop != None) { + if (XGetWindowProperty(x11_display, windows_data[win_index], strut_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &strut_len, &remaining, &strut_data) == Success) { + strut_found = true; + } + } + } + if (!g_bad_window && strut_found && (format == 32) && (strut_len >= 4) && strut_data) { + long *struts = (long *)strut_data; + + long left = struts[0]; + long right = struts[1]; + long top = struts[2]; + long bottom = struts[3]; + + long left_start_y, left_end_y, right_start_y, right_end_y; + long top_start_x, top_end_x, bottom_start_x, bottom_end_x; + + if (strut_len >= 12) { + left_start_y = struts[4]; + left_end_y = struts[5]; + right_start_y = struts[6]; + right_end_y = struts[7]; + top_start_x = struts[8]; + top_end_x = struts[9]; + bottom_start_x = struts[10]; + bottom_end_x = struts[11]; + } else { + left_start_y = 0; + left_end_y = desktop_rect.size.y; + right_start_y = 0; + right_end_y = desktop_rect.size.y; + top_start_x = 0; + top_end_x = desktop_rect.size.x; + bottom_start_x = 0; + bottom_end_x = desktop_rect.size.x; + } + + const Point2i &pos = desktop_rect.position; + const Size2i &size = desktop_rect.size; + + Rect2i left_rect(pos.x, pos.y + left_start_y, left, left_end_y - left_start_y); + if (left_rect.size.x > 0) { + Rect2i intersection = rect.intersection(left_rect); + if (!intersection.has_no_area() && intersection.size.x < rect.size.x) { + rect.position.x = left_rect.size.x; + rect.size.x = rect.size.x - intersection.size.x; + } + } + + Rect2i right_rect(pos.x + size.x - right, pos.y + right_start_y, right, right_end_y - right_start_y); + if (right_rect.size.x > 0) { + Rect2i intersection = rect.intersection(right_rect); + if (!intersection.has_no_area() && right_rect.size.x < rect.size.x) { + rect.size.x = intersection.position.x - rect.position.x; + } + } + + Rect2i top_rect(pos.x + top_start_x, pos.y, top_end_x - top_start_x, top); + if (top_rect.size.y > 0) { + Rect2i intersection = rect.intersection(top_rect); + if (!intersection.has_no_area() && intersection.size.y < rect.size.y) { + rect.position.y = top_rect.size.y; + rect.size.y = rect.size.y - intersection.size.y; + } + } + + Rect2i bottom_rect(pos.x + bottom_start_x, pos.y + size.y - bottom, bottom_end_x - bottom_start_x, bottom); + if (bottom_rect.size.y > 0) { + Rect2i intersection = rect.intersection(bottom_rect); + if (!intersection.has_no_area() && right_rect.size.y < rect.size.y) { + rect.size.y = intersection.position.y - rect.position.y; + } + } + } + if (strut_data) { + XFree(strut_data); + } + } + + // Restore default error handler. + XSetErrorHandler(oldHandler); + } + } + } + if (clients_data) { + XFree(clients_data); + } + } + } + + // Single screen or fallback for multi screen. + if (use_simple_method) { + // Get desktop available size from the global work area. + Atom workarea_prop = XInternAtom(x11_display, "_NET_WORKAREA", True); + if (workarea_prop != None) { + unsigned long workarea_len = 0; + unsigned char *workarea_data = nullptr; + if (XGetWindowProperty(x11_display, x11_window, workarea_prop, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &workarea_len, &remaining, &workarea_data) == Success) { + if ((format == 32) && (workarea_len >= ((desktop_index + 1) * 4)) && workarea_data) { + long *rect_data = (long *)workarea_data; + int data_offset = desktop_index * 4; + Rect2i workarea_rect; + workarea_rect.position.x = rect_data[data_offset]; + workarea_rect.position.y = rect_data[data_offset + 1]; + workarea_rect.size.x = rect_data[data_offset + 2]; + workarea_rect.size.y = rect_data[data_offset + 3]; + + // Intersect with actual monitor size to get a proper approximation in multi-screen setup. + if (!is_multiscreen) { + rect = workarea_rect; + } else if (rect.intersects(workarea_rect)) { + rect = rect.intersection(workarea_rect); + } + } + } + if (workarea_data) { + XFree(workarea_data); + } + } } - Rect2i rect = Rect2i(xsi[p_screen].x_org, xsi[p_screen].y_org, xsi[p_screen].width, xsi[p_screen].height); - XFree(xsi); return rect; } @@ -666,20 +1078,40 @@ bool DisplayServerX11::screen_is_touchscreen(int p_screen) const { return DisplayServer::screen_is_touchscreen(p_screen); } +#ifdef DBUS_ENABLED +void DisplayServerX11::screen_set_keep_on(bool p_enable) { + if (screen_is_kept_on() == p_enable) { + return; + } + + if (p_enable) { + screensaver->inhibit(); + } else { + screensaver->uninhibit(); + } + + keep_screen_on = p_enable; +} + +bool DisplayServerX11::screen_is_kept_on() const { + return keep_screen_on; +} +#endif + Vector<DisplayServer::WindowID> DisplayServerX11::get_window_list() const { _THREAD_SAFE_METHOD_ Vector<int> ret; - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - ret.push_back(E->key()); + for (const KeyValue<WindowID, WindowData> &E : windows) { + ret.push_back(E.key); } return ret; } -DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { _THREAD_SAFE_METHOD_ - WindowID id = _create_window(p_mode, p_flags, p_rect); + WindowID id = _create_window(p_mode, p_vsync_mode, p_flags, p_rect); for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, id); @@ -692,7 +1124,9 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, u void DisplayServerX11::show_window(WindowID p_id) { _THREAD_SAFE_METHOD_ - WindowData &wd = windows[p_id]; + const WindowData &wd = windows[p_id]; + + DEBUG_LOG_X11("show_window: %lu (%u) \n", wd.x11_window, p_id); XMapWindow(x11_display, wd.x11_window); } @@ -720,10 +1154,17 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { context_vulkan->window_destroy(p_id); } #endif +#ifdef GLES3_ENABLED + if (gl_manager) { + gl_manager->window_destroy(p_id); + } +#endif + XUnmapWindow(x11_display, wd.x11_window); XDestroyWindow(x11_display, wd.x11_window); if (wd.xic) { XDestroyIC(wd.xic); + wd.xic = nullptr; } windows.erase(p_id); @@ -746,8 +1187,8 @@ DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const WindowID found_window = INVALID_WINDOW_ID; WindowID parent_window = INVALID_WINDOW_ID; unsigned int focus_order = 0; - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - const WindowData &wd = E->get(); + for (const KeyValue<WindowID, WindowData> &E : windows) { + const WindowData &wd = E.value; // Discard windows with no focus. if (wd.focus_order == 0) { @@ -755,7 +1196,7 @@ DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const } // Find topmost window which contains the given position. - WindowID window_id = E->key(); + WindowID window_id = E.key; Rect2i win_rect = Rect2i(window_get_position(window_id), window_get_size(window_id)); if (win_rect.has_point(p_position)) { // For siblings, pick the window which was focused last. @@ -780,7 +1221,9 @@ void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window Atom _net_wm_name = XInternAtom(x11_display, "_NET_WM_NAME", false); Atom utf8_string = XInternAtom(x11_display, "UTF8_STRING", false); - XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); + if (_net_wm_name != None && utf8_string != None) { + XChangeProperty(x11_display, wd.x11_window, _net_wm_name, utf8_string, 8, PropModeReplace, (unsigned char *)p_title.utf8().get_data(), p_title.utf8().length()); + } } void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window) { @@ -858,22 +1301,38 @@ void DisplayServerX11::window_set_drop_files_callback(const Callable &p_callable int DisplayServerX11::window_get_current_screen(WindowID p_window) const { _THREAD_SAFE_METHOD_ - ERR_FAIL_COND_V(!windows.has(p_window), -1); + int count = get_screen_count(); + if (count < 2) { + // Early exit with single monitor. + return 0; + } + + ERR_FAIL_COND_V(!windows.has(p_window), 0); const WindowData &wd = windows[p_window]; - int x, y; - Window child; - XTranslateCoordinates(x11_display, wd.x11_window, DefaultRootWindow(x11_display), 0, 0, &x, &y, &child); + const Rect2i window_rect(wd.position, wd.size); - int count = get_screen_count(); + // 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++) { - Point2i pos = screen_get_position(i); - Size2i size = screen_get_size(i); - if ((x >= pos.x && x < pos.x + size.width) && (y >= pos.y && y < pos.y + size.height)) { - return 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 0; + + return screen_index; +} + +void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_id) { +#if defined(GLES3_ENABLED) + if (gl_manager) + gl_manager->window_make_current(p_window_id); +#endif } void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window) { @@ -882,11 +1341,13 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd = windows[p_window]; - int count = get_screen_count(); - if (p_screen >= count) { - return; + if (p_screen == SCREEN_OF_MAIN_WINDOW) { + p_screen = window_get_current_screen(); } + // Check if screen is valid + ERR_FAIL_INDEX(p_screen, get_screen_count()); + if (window_get_mode(p_window) == WINDOW_MODE_FULLSCREEN) { Point2i position = screen_get_position(p_screen); Size2i size = screen_get_size(p_screen); @@ -911,6 +1372,8 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent WindowID prev_parent = wd_window.transient_parent; ERR_FAIL_COND(prev_parent == p_parent); + DEBUG_LOG_X11("window_set_transient: %lu (%u), prev_parent=%u, parent=%u\n", wd_window.x11_window, p_window, prev_parent, p_parent); + ERR_FAIL_COND_MSG(wd_window.on_top, "Windows with the 'on top' can't become transient."); if (p_parent == INVALID_WINDOW_ID) { //remove transient @@ -925,10 +1388,10 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent XSetTransientForHint(x11_display, wd_window.x11_window, None); - // Set focus to parent sub window to avoid losing all focus with nested menus. + // Set focus to parent sub window to avoid losing all focus when closing a nested sub-menu. // RevertToPointerRoot is used to make sure we don't lose all focus in case // a subwindow and its parent are both destroyed. - if (wd_window.menu_type && !wd_window.no_focus) { + if (wd_window.menu_type && !wd_window.no_focus && wd_window.focused) { if (!wd_parent.no_focus) { XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); } @@ -1170,6 +1633,10 @@ bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_a unsigned char *data = nullptr; bool retval = false; + if (property == None) { + return false; + } + int result = XGetWindowProperty( x11_display, wd.x11_window, @@ -1258,7 +1725,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { hints.flags = 2; hints.decorations = 0; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } if (p_enabled) { @@ -1285,7 +1754,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { // set bypass compositor hint Atom bypass_compositor = XInternAtom(x11_display, "_NET_WM_BYPASS_COMPOSITOR", False); unsigned long compositing_disable_on = p_enabled ? 1 : 0; - XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1); + if (bypass_compositor != None) { + XChangeProperty(x11_display, wd.x11_window, bypass_compositor, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&compositing_disable_on, 1); + } XFlush(x11_display); @@ -1299,7 +1770,9 @@ void DisplayServerX11::_set_wm_fullscreen(WindowID p_window, bool p_enabled) { hints.flags = 2; hints.decorations = window_get_flag(WINDOW_FLAG_BORDERLESS, p_window) ? 0 : 1; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } } @@ -1434,6 +1907,10 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c { // Test minimized. // Using ICCCM -- Inter-Client Communication Conventions Manual Atom property = XInternAtom(x11_display, "WM_STATE", True); + if (property == None) { + return WINDOW_MODE_WINDOWED; + } + Atom type; int format; unsigned long len; @@ -1489,7 +1966,9 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo hints.flags = 2; hints.decorations = p_enabled ? 0 : 1; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } // Preserve window size window_set_size(window_get_size(p_window), p_window); @@ -1628,8 +2107,8 @@ bool DisplayServerX11::window_can_draw(WindowID p_window) const { bool DisplayServerX11::can_any_window_draw() const { _THREAD_SAFE_METHOD_ - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if (window_get_mode(E->key()) != WINDOW_MODE_MINIMIZED) { + for (const KeyValue<WindowID, WindowData> &E : windows) { + if (window_get_mode(E.key) != WINDOW_MODE_MINIMIZED) { return true; } } @@ -1649,10 +2128,16 @@ void DisplayServerX11::window_set_ime_active(const bool p_active, WindowID p_win return; } + // Block events polling while changing input focus + // because it triggers some event polling internally. if (p_active) { - XSetICFocus(wd.xic); + { + MutexLock mutex_lock(events_mutex); + XSetICFocus(wd.xic); + } window_set_ime_position(wd.im_position, p_window); } else { + MutexLock mutex_lock(events_mutex); XUnsetICFocus(wd.xic); } } @@ -1673,7 +2158,14 @@ void DisplayServerX11::window_set_ime_position(const Point2i &p_pos, WindowID p_ spot.x = short(p_pos.x); spot.y = short(p_pos.y); XVaNestedList preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, nullptr); - XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr); + + { + // Block events polling during this call + // because it triggers some event polling internally. + MutexLock mutex_lock(events_mutex); + XSetICValues(wd.xic, XNPreeditAttributes, preedit_attr, nullptr); + } + XFree(preedit_attr); } @@ -1688,12 +2180,12 @@ void DisplayServerX11::cursor_set_shape(CursorShape p_shape) { if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { if (cursors[p_shape] != None) { - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]); + for (const KeyValue<WindowID, WindowData> &E : windows) { + XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]); } } else if (cursors[CURSOR_ARROW] != None) { - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - XDefineCursor(x11_display, E->get().x11_window, cursors[CURSOR_ARROW]); + for (const KeyValue<WindowID, WindowData> &E : windows) { + XDefineCursor(x11_display, E.value.x11_window, cursors[CURSOR_ARROW]); } } } @@ -1727,7 +2219,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape Rect2i atlas_rect; if (texture.is_valid()) { - image = texture->get_data(); + image = texture->get_image(); } if (!image.is_valid() && atlas_texture.is_valid()) { @@ -1750,7 +2242,7 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape 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_data(); + image = texture->get_image(); ERR_FAIL_COND(!image.is_valid()); @@ -1791,8 +2283,8 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape if (p_shape == current_cursor) { if (mouse_mode == MOUSE_MODE_VISIBLE || mouse_mode == MOUSE_MODE_CONFINED) { - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - XDefineCursor(x11_display, E->get().x11_window, cursors[p_shape]); + for (const KeyValue<WindowID, WindowData> &E : windows) { + XDefineCursor(x11_display, E.value.x11_window, cursors[p_shape]); } } } @@ -1822,7 +2314,7 @@ int DisplayServerX11::keyboard_get_layout_count() const { XkbGetNames(x11_display, XkbSymbolsNameMask, kbd); const Atom *groups = kbd->names->groups; - if (kbd->ctrls != NULL) { + if (kbd->ctrls != nullptr) { _group_count = kbd->ctrls->num_groups; } else { while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { @@ -1856,7 +2348,7 @@ String DisplayServerX11::keyboard_get_layout_language(int p_index) const { int _group_count = 0; const Atom *groups = kbd->names->groups; - if (kbd->ctrls != NULL) { + if (kbd->ctrls != nullptr) { _group_count = kbd->ctrls->num_groups; } else { while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { @@ -1895,7 +2387,7 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const { int _group_count = 0; const Atom *groups = kbd->names->groups; - if (kbd->ctrls != NULL) { + if (kbd->ctrls != nullptr) { _group_count = kbd->ctrls->num_groups; } else { while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { @@ -1915,29 +2407,48 @@ String DisplayServerX11::keyboard_get_layout_name(int p_index) const { return ret; } +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); + if (xkeysym >= 'a' && xkeysym <= 'z') { + xkeysym -= ('a' - 'A'); + } + + Key key = KeyMappingX11::get_keycode(xkeysym); + // If not found, fallback to QWERTY. + // This should match the behavior of the event pump + if (key == Key::NONE) { + return p_keycode; + } + return (Key)(key | modifiers); +} + DisplayServerX11::Property DisplayServerX11::_read_property(Display *p_display, Window p_window, Atom p_property) { - Atom actual_type; - int actual_format; - unsigned long nitems; - unsigned long bytes_after; + Atom actual_type = None; + int actual_format = 0; + unsigned long nitems = 0; + unsigned long bytes_after = 0; unsigned char *ret = nullptr; int read_bytes = 1024; - //Keep trying to read the property until there are no - //bytes unread. - do { - if (ret != nullptr) { - XFree(ret); - } + // Keep trying to read the property until there are no bytes unread. + if (p_property != None) { + do { + if (ret != nullptr) { + XFree(ret); + } - XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType, - &actual_type, &actual_format, &nitems, &bytes_after, - &ret); + XGetWindowProperty(p_display, p_window, p_property, 0, read_bytes, False, AnyPropertyType, + &actual_type, &actual_format, &nitems, &bytes_after, + &ret); - read_bytes *= 2; + read_bytes *= 2; - } while (bytes_after != 0); + } while (bytes_after != 0); + } Property p = { ret, actual_format, (int)nitems, actual_type }; @@ -1975,14 +2486,14 @@ static Atom pick_target_from_atoms(Display *p_disp, Atom p_t1, Atom p_t2, Atom p } void DisplayServerX11::_get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state) { - state->set_shift((p_x11_state & ShiftMask)); - state->set_control((p_x11_state & ControlMask)); - state->set_alt((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt - state->set_metakey((p_x11_state & Mod4Mask)); + state->set_shift_pressed((p_x11_state & ShiftMask)); + state->set_ctrl_pressed((p_x11_state & ControlMask)); + state->set_alt_pressed((p_x11_state & Mod1Mask /*|| p_x11_state&Mod5Mask*/)); //altgr should not count as alt + state->set_meta_pressed((p_x11_state & Mod4Mask)); } -unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button, int p_x11_type) { - unsigned int mask = 1 << (p_x11_button - 1); +MouseButton DisplayServerX11::_get_mouse_button_state(MouseButton p_x11_button, int p_x11_type) { + MouseButton mask = mouse_button_to_mask(p_x11_button); if (p_x11_type == ButtonPress) { last_button_state |= mask; @@ -1993,7 +2504,7 @@ unsigned int DisplayServerX11::_get_mouse_button_state(unsigned int p_x11_button return last_button_state; } -void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo) { +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]; // X11 functions don't know what const is XKeyEvent *xkeyevent = p_event; @@ -2013,7 +2524,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, // still works in half the cases. (won't handle deadkeys) // For more complex input methods (deadkeys and more advanced) // you have to use XmbLookupString (??). - // So.. then you have to chosse which of both results + // So then you have to choose which of both results // you want to keep. // This is a real bizarreness and cpu waster. @@ -2053,10 +2564,10 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, if (status == XLookupChars) { bool keypress = xkeyevent->type == KeyPress; - unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); - unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); + Key keycode = KeyMappingX11::get_keycode(keysym_keycode); + Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); - if (keycode >= 'a' && keycode <= 'z') { + if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) { keycode -= 'a' - 'A'; } @@ -2064,13 +2575,13 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, tmp.parse_utf8(utf8string, utf8bytes); for (int i = 0; i < tmp.length(); i++) { Ref<InputEventKey> k; - k.instance(); - if (physical_keycode == 0 && keycode == 0 && tmp[i] == 0) { + k.instantiate(); + if (physical_keycode == Key::NONE && keycode == Key::NONE && tmp[i] == 0) { continue; } - if (keycode == 0) { - keycode = physical_keycode; + if (keycode == Key::NONE) { + keycode = (Key)physical_keycode; } _get_key_modifier_state(xkeyevent->state, k); @@ -2082,18 +2593,18 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, k->set_keycode(keycode); - k->set_physical_keycode(physical_keycode); + k->set_physical_keycode((Key)physical_keycode); k->set_echo(false); - if (k->get_keycode() == KEY_BACKTAB) { + if (k->get_keycode() == Key::BACKTAB) { //make it consistent across platforms. - k->set_keycode(KEY_TAB); - k->set_physical_keycode(KEY_TAB); - k->set_shift(true); + k->set_keycode(Key::TAB); + k->set_physical_keycode(Key::TAB); + k->set_shift_pressed(true); } - Input::get_singleton()->accumulate_input_event(k); + Input::get_singleton()->parse_input_event(k); } memfree(utf8string); return; @@ -2117,8 +2628,8 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, // KeyMappingX11 just translated the X11 keysym to a PIGUI // keysym, so it works in all platforms the same. - unsigned int keycode = KeyMappingX11::get_keycode(keysym_keycode); - unsigned int physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); + Key keycode = KeyMappingX11::get_keycode(keysym_keycode); + Key physical_keycode = KeyMappingX11::get_scancode(xkeyevent->keycode); /* Phase 3, obtain a unicode character from the keysym */ @@ -2130,7 +2641,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, /* Phase 4, determine if event must be filtered */ // This seems to be a side-effect of using XIM. - // XEventFilter looks like a core X11 function, + // XFilterEvent looks like a core X11 function, // but it's actually just used to see if we must // ignore a deadkey, or events XIM determines // must not reach the actual gui. @@ -2138,12 +2649,12 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, bool keypress = xkeyevent->type == KeyPress; - if (physical_keycode == 0 && keycode == 0 && unicode == 0) { + if (physical_keycode == Key::NONE && keycode == Key::NONE && unicode == 0) { return; } - if (keycode == 0) { - keycode = physical_keycode; + if (keycode == Key::NONE) { + keycode = (Key)physical_keycode; } /* Phase 5, determine modifier mask */ @@ -2155,7 +2666,7 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, //print_verbose("mod1: "+itos(xkeyevent->state&Mod1Mask)+" mod 5: "+itos(xkeyevent->state&Mod5Mask)); Ref<InputEventKey> k; - k.instance(); + k.instantiate(); k->set_window_id(p_window); _get_key_modifier_state(xkeyevent->state, k); @@ -2164,17 +2675,16 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, // Echo characters in X11 are a keyrelease and a keypress // one after the other with the (almot) same timestamp. - // To detect them, i use XPeekEvent and check that their - // difference in time is below a threshold. + // To detect them, i compare to the next event in list and + // check that their difference in time is below a threshold. if (xkeyevent->type != KeyPress) { p_echo = false; // make sure there are events pending, // so this call won't block. - if (XPending(x11_display) > 0) { - XEvent peek_event; - XPeekEvent(x11_display, &peek_event); + if (p_event_index + 1 < p_events.size()) { + XEvent &peek_event = p_events[p_event_index + 1]; // I'm using a threshold of 5 msecs, // since sometimes there seems to be a little @@ -2189,9 +2699,9 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, KeySym rk; XLookupString((XKeyEvent *)&peek_event, str, 256, &rk, nullptr); if (rk == keysym_keycode) { - XEvent event; - XNextEvent(x11_display, &event); //erase next event - _handle_key_event(p_window, (XKeyEvent *)&event, true); + // Consume to next event. + ++p_event_index; + _handle_key_event(p_window, (XKeyEvent *)&peek_event, p_events, p_event_index, true); return; //ignore current, echo next } } @@ -2206,33 +2716,33 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, k->set_pressed(keypress); - if (keycode >= 'a' && keycode <= 'z') { - keycode -= 'a' - 'A'; + if (keycode >= Key::A + 32 && keycode <= Key::Z + 32) { + keycode -= int('a' - 'A'); } k->set_keycode(keycode); - k->set_physical_keycode(physical_keycode); + k->set_physical_keycode((Key)physical_keycode); k->set_unicode(unicode); k->set_echo(p_echo); - if (k->get_keycode() == KEY_BACKTAB) { + if (k->get_keycode() == Key::BACKTAB) { //make it consistent across platforms. - k->set_keycode(KEY_TAB); - k->set_physical_keycode(KEY_TAB); - k->set_shift(true); + k->set_keycode(Key::TAB); + k->set_physical_keycode(Key::TAB); + k->set_shift_pressed(true); } //don't set mod state if modifier keys are released by themselves //else event.is_action() will not work correctly here if (!k->is_pressed()) { - if (k->get_keycode() == KEY_SHIFT) { - k->set_shift(false); - } else if (k->get_keycode() == KEY_CONTROL) { - k->set_control(false); - } else if (k->get_keycode() == KEY_ALT) { - k->set_alt(false); - } else if (k->get_keycode() == KEY_META) { - k->set_metakey(false); + if (k->get_keycode() == Key::SHIFT) { + k->set_shift_pressed(false); + } else if (k->get_keycode() == Key::CTRL) { + k->set_ctrl_pressed(false); + } else if (k->get_keycode() == Key::ALT) { + k->set_alt_pressed(false); + } else if (k->get_keycode() == Key::META) { + k->set_meta_pressed(false); } } @@ -2243,7 +2753,125 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, } } - Input::get_singleton()->accumulate_input_event(k); + Input::get_singleton()->parse_input_event(k); +} + +Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const { + if (p_target == XInternAtom(x11_display, "TARGETS", 0)) { + // Request to list all supported targets. + Atom data[9]; + data[0] = XInternAtom(x11_display, "TARGETS", 0); + data[1] = XInternAtom(x11_display, "SAVE_TARGETS", 0); + data[2] = XInternAtom(x11_display, "MULTIPLE", 0); + data[3] = XInternAtom(x11_display, "UTF8_STRING", 0); + data[4] = XInternAtom(x11_display, "COMPOUND_TEXT", 0); + data[5] = XInternAtom(x11_display, "TEXT", 0); + data[6] = XA_STRING; + data[7] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0); + data[8] = XInternAtom(x11_display, "text/plain", 0); + + XChangeProperty(x11_display, + p_requestor, + p_property, + XA_ATOM, + 32, + PropModeReplace, + (unsigned char *)&data, + sizeof(data) / sizeof(data[0])); + return p_property; + } else if (p_target == XInternAtom(x11_display, "SAVE_TARGETS", 0)) { + // Request to check if SAVE_TARGETS is supported, nothing special to do. + XChangeProperty(x11_display, + p_requestor, + p_property, + XInternAtom(x11_display, "NULL", False), + 32, + PropModeReplace, + nullptr, + 0); + return p_property; + } else if (p_target == XInternAtom(x11_display, "UTF8_STRING", 0) || + p_target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) || + p_target == XInternAtom(x11_display, "TEXT", 0) || + p_target == XA_STRING || + p_target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) || + p_target == XInternAtom(x11_display, "text/plain", 0)) { + // Directly using internal clipboard because we know our window + // is the owner during a selection request. + CharString clip; + static const char *target_type = "PRIMARY"; + if (p_selection != None && String(XGetAtomName(x11_display, p_selection)) == target_type) { + clip = internal_clipboard_primary.utf8(); + } else { + clip = internal_clipboard.utf8(); + } + XChangeProperty(x11_display, + p_requestor, + p_property, + p_target, + 8, + PropModeReplace, + (unsigned char *)clip.get_data(), + clip.length()); + return p_property; + } else { + char *target_name = XGetAtomName(x11_display, p_target); + printf("Target '%s' not supported.\n", target_name); + if (target_name) { + XFree(target_name); + } + return None; + } +} + +void DisplayServerX11::_handle_selection_request_event(XSelectionRequestEvent *p_event) const { + XEvent respond; + if (p_event->target == XInternAtom(x11_display, "MULTIPLE", 0)) { + // Request for multiple target conversions at once. + Atom atom_pair = XInternAtom(x11_display, "ATOM_PAIR", False); + respond.xselection.property = None; + + Atom type; + int format; + unsigned long len; + unsigned long remaining; + unsigned char *data = nullptr; + if (XGetWindowProperty(x11_display, p_event->requestor, p_event->property, 0, LONG_MAX, False, atom_pair, &type, &format, &len, &remaining, &data) == Success) { + if ((len >= 2) && data) { + Atom *targets = (Atom *)data; + for (uint64_t i = 0; i < len; i += 2) { + Atom target = targets[i]; + Atom &property = targets[i + 1]; + property = _process_selection_request_target(target, p_event->requestor, property, p_event->selection); + } + + XChangeProperty(x11_display, + p_event->requestor, + p_event->property, + atom_pair, + 32, + PropModeReplace, + (unsigned char *)targets, + len); + + respond.xselection.property = p_event->property; + } + XFree(data); + } + } else { + // Request for target conversion. + respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property, p_event->selection); + } + + respond.xselection.type = SelectionNotify; + respond.xselection.display = p_event->display; + respond.xselection.requestor = p_event->requestor; + respond.xselection.selection = p_event->selection; + respond.xselection.target = p_event->target; + respond.xselection.time = p_event->time; + + XSendEvent(x11_display, p_event->requestor, True, NoEventMask, &respond); + XFlush(x11_display); } void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data, @@ -2252,8 +2880,8 @@ void DisplayServerX11::_xim_destroy_callback(::XIM im, ::XPointer client_data, DisplayServerX11 *ds = reinterpret_cast<DisplayServerX11 *>(client_data); ds->xim = nullptr; - for (Map<WindowID, WindowData>::Element *E = ds->windows.front(); E; E = E->next()) { - E->get().xic = nullptr; + for (KeyValue<WindowID, WindowData> &E : ds->windows) { + E.value.xic = nullptr; } } @@ -2261,9 +2889,9 @@ void DisplayServerX11::_window_changed(XEvent *event) { WindowID window_id = MAIN_WINDOW_ID; // Assign the event to the relevant window - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if (event->xany.window == E->get().x11_window) { - window_id = E->key(); + for (const KeyValue<WindowID, WindowData> &E : windows) { + if (event->xany.window == E.value.x11_window) { + window_id = E.key; break; } } @@ -2303,8 +2931,12 @@ void DisplayServerX11::_window_changed(XEvent *event) { context_vulkan->window_resize(window_id, wd.size.width, wd.size.height); } #endif +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->window_resize(window_id, wd.size.width, wd.size.height); + } +#endif - print_line("DisplayServer::_window_changed: " + itos(window_id) + " rect: " + new_rect); if (!wd.rect_changed_callback.is_null()) { Rect2i r = new_rect; @@ -2338,8 +2970,8 @@ void DisplayServerX11::_dispatch_input_event(const Ref<InputEvent> &p_event) { callable.call((const Variant **)&evp, 1, ret, ce); } else { //send to all windows - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - Callable callable = E->get().input_event_callback; + for (KeyValue<WindowID, WindowData> &E : windows) { + Callable callable = E.value.input_event_callback; if (callable.is_null()) { continue; } @@ -2358,6 +2990,83 @@ void DisplayServerX11::_send_window_event(const WindowData &wd, WindowEvent p_ev } } +void DisplayServerX11::_poll_events_thread(void *ud) { + DisplayServerX11 *display_server = (DisplayServerX11 *)ud; + display_server->_poll_events(); +} + +Bool DisplayServerX11::_predicate_all_events(Display *display, XEvent *event, XPointer arg) { + // Just accept all events. + return True; +} + +bool DisplayServerX11::_wait_for_events() const { + int x11_fd = ConnectionNumber(x11_display); + fd_set in_fds; + + XFlush(x11_display); + + FD_ZERO(&in_fds); + FD_SET(x11_fd, &in_fds); + + struct timeval tv; + tv.tv_usec = 0; + tv.tv_sec = 1; + + // Wait for next event or timeout. + int num_ready_fds = select(x11_fd + 1, &in_fds, nullptr, nullptr, &tv); + + if (num_ready_fds > 0) { + // Event received. + return true; + } else { + // Error or timeout. + if (num_ready_fds < 0) { + ERR_PRINT("_wait_for_events: select error: " + itos(errno)); + } + return false; + } +} + +void DisplayServerX11::_poll_events() { + while (!events_thread_done.is_set()) { + _wait_for_events(); + + // Process events from the queue. + { + MutexLock mutex_lock(events_mutex); + + _check_pending_events(polled_events); + } + } +} + +void DisplayServerX11::_check_pending_events(LocalVector<XEvent> &r_events) { + // Flush to make sure to gather all pending events. + XFlush(x11_display); + + // Non-blocking wait for next event and remove it from the queue. + XEvent ev; + while (XCheckIfEvent(x11_display, &ev, _predicate_all_events, nullptr)) { + // Check if the input manager wants to process the event. + if (XFilterEvent(&ev, None)) { + // Event has been filtered by the Input Manager, + // it has to be ignored and a new one will be received. + continue; + } + + // Handle selection request events directly in the event thread, because + // communication through the x server takes several events sent back and forth + // and we don't want to block other programs while processing only one each frame. + if (ev.type == SelectionRequest) { + _handle_selection_request_event(&(ev.xselectionrequest)); + continue; + } + + r_events.push_back(ev); + } +} + void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ @@ -2369,8 +3078,8 @@ void DisplayServerX11::process_events() { if (app_focused) { //verify that one of the windows has focus, else send focus out notification bool focus_found = false; - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if (E->get().focused) { + for (const KeyValue<WindowID, WindowData> &E : windows) { + if (E.value.focused) { focus_found = true; break; } @@ -2395,26 +3104,32 @@ void DisplayServerX11::process_events() { do_mouse_warp = false; // Is the current mouse mode one where it needs to be grabbed. - bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED; + bool mouse_mode_grab = mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN; xi.pressure = 0; xi.tilt = Vector2(); xi.pressure_supported = false; - while (XPending(x11_display) > 0) { - XEvent event; - XNextEvent(x11_display, &event); + LocalVector<XEvent> events; + { + // Block events polling while flushing events. + MutexLock mutex_lock(events_mutex); + events = polled_events; + polled_events.clear(); - if (XFilterEvent(&event, None)) { - continue; - } + // Check for more pending events to avoid an extra frame delay. + _check_pending_events(events); + } + + for (uint32_t event_index = 0; event_index < events.size(); ++event_index) { + XEvent &event = events[event_index]; WindowID window_id = MAIN_WINDOW_ID; // Assign the event to the relevant window - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - if (event.xany.window == E->get().x11_window) { - window_id = E->key(); + for (const KeyValue<WindowID, WindowData> &E : windows) { + if (event.xany.window == E.value.x11_window) { + window_id = E.key; break; } } @@ -2463,7 +3178,7 @@ void DisplayServerX11::process_events() { if (pen_pressure_range != Vector2()) { xi.pressure_supported = true; xi.pressure = (*values - pen_pressure_range[0]) / - (pen_pressure_range[1] - pen_pressure_range[0]); + (pen_pressure_range[1] - pen_pressure_range[0]); } } @@ -2522,15 +3237,12 @@ void DisplayServerX11::process_events() { xi.last_relative_time = raw_event->time; } break; #ifdef TOUCH_ENABLED - case XI_TouchBegin: // Fall-through - // Disabled hand-in-hand with the grabbing - //XIAllowTouchEvents(x11_display, event_data->deviceid, event_data->detail, x11_window, XIAcceptTouch); - + case XI_TouchBegin: case XI_TouchEnd: { bool is_begin = event_data->evtype == XI_TouchBegin; Ref<InputEventScreenTouch> st; - st.instance(); + st.instantiate(); st->set_window_id(window_id); st->set_index(index); st->set_position(pos); @@ -2546,13 +3258,13 @@ void DisplayServerX11::process_events() { // in a spurious mouse motion event being sent to Godot; remember it to be able to filter it out xi.mouse_pos_to_filter = pos; } - Input::get_singleton()->accumulate_input_event(st); + Input::get_singleton()->parse_input_event(st); } else { if (!xi.state.has(index)) { // Defensive break; } xi.state.erase(index); - Input::get_singleton()->accumulate_input_event(st); + Input::get_singleton()->parse_input_event(st); } } break; @@ -2564,12 +3276,12 @@ void DisplayServerX11::process_events() { if (curr_pos_elem->value() != pos) { Ref<InputEventScreenDrag> sd; - sd.instance(); + sd.instantiate(); sd->set_window_id(window_id); sd->set_index(index); sd->set_position(pos); sd->set_relative(pos - curr_pos_elem->value()); - Input::get_singleton()->accumulate_input_event(sd); + Input::get_singleton()->parse_input_event(sd); curr_pos_elem->value() = pos; } @@ -2637,6 +3349,13 @@ void DisplayServerX11::process_events() { wd.focused = true; + if (wd.xic) { + // Block events polling while changing input focus + // because it triggers some event polling internally. + MutexLock mutex_lock(events_mutex); + XSetICFocus(wd.xic); + } + // Keep track of focus order for overlapping windows. static unsigned int focus_order = 0; wd.focus_order = ++focus_order; @@ -2646,17 +3365,17 @@ void DisplayServerX11::process_events() { if (mouse_mode_grab) { // Show and update the cursor if confined and the window regained focus. - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { + for (const KeyValue<WindowID, WindowData> &E : windows) { if (mouse_mode == MOUSE_MODE_CONFINED) { - XUndefineCursor(x11_display, E->get().x11_window); - } else if (mouse_mode == MOUSE_MODE_CAPTURED) { // or re-hide it in captured mode - XDefineCursor(x11_display, E->get().x11_window, null_cursor); + XUndefineCursor(x11_display, E.value.x11_window); + } else if (mouse_mode == MOUSE_MODE_CAPTURED || mouse_mode == MOUSE_MODE_CONFINED_HIDDEN) { // Or re-hide it. + XDefineCursor(x11_display, E.value.x11_window, null_cursor); } XGrabPointer( - x11_display, E->get().x11_window, True, + x11_display, E.value.x11_window, True, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, - GrabModeAsync, GrabModeAsync, E->get().x11_window, None, CurrentTime); + GrabModeAsync, GrabModeAsync, E.value.x11_window, None, CurrentTime); } } #ifdef TOUCH_ENABLED @@ -2665,9 +3384,6 @@ void DisplayServerX11::process_events() { XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask); }*/ #endif - if (wd.xic) { - XSetICFocus(wd.xic); - } if (!app_focused) { if (OS::get_singleton()->get_main_loop()) { @@ -2684,15 +3400,22 @@ void DisplayServerX11::process_events() { wd.focused = false; + if (wd.xic) { + // Block events polling while changing input focus + // because it triggers some event polling internally. + MutexLock mutex_lock(events_mutex); + XUnsetICFocus(wd.xic); + } + Input::get_singleton()->release_pressed_events(); _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT); if (mouse_mode_grab) { - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { + for (const KeyValue<WindowID, WindowData> &E : windows) { //dear X11, I try, I really try, but you never work, you do whathever you want. if (mouse_mode == MOUSE_MODE_CAPTURED) { // Show the cursor if we're in captured mode so it doesn't look weird. - XUndefineCursor(x11_display, E->get().x11_window); + XUndefineCursor(x11_display, E.value.x11_window); } } XUngrabPointer(x11_display, CurrentTime); @@ -2704,19 +3427,16 @@ void DisplayServerX11::process_events() { }*/ // Release every pointer to avoid sticky points - for (Map<int, Vector2>::Element *E = xi.state.front(); E; E = E->next()) { + for (const KeyValue<int, Vector2> &E : xi.state) { Ref<InputEventScreenTouch> st; - st.instance(); - st->set_index(E->key()); + st.instantiate(); + st->set_index(E.key); st->set_window_id(window_id); - st->set_position(E->get()); - Input::get_singleton()->accumulate_input_event(st); + st->set_position(E.value); + Input::get_singleton()->parse_input_event(st); } xi.state.clear(); #endif - if (wd.xic) { - XSetICFocus(wd.xic); - } } break; case ConfigureNotify: { @@ -2744,15 +3464,15 @@ void DisplayServerX11::process_events() { } Ref<InputEventMouseButton> mb; - mb.instance(); + mb.instantiate(); mb->set_window_id(window_id); _get_key_modifier_state(event.xbutton.state, mb); - mb->set_button_index(event.xbutton.button); - if (mb->get_button_index() == 2) { - mb->set_button_index(3); - } else if (mb->get_button_index() == 3) { - mb->set_button_index(2); + mb->set_button_index((MouseButton)event.xbutton.button); + if (mb->get_button_index() == MouseButton::RIGHT) { + mb->set_button_index(MouseButton::MIDDLE); + } else if (mb->get_button_index() == MouseButton::MIDDLE) { + mb->set_button_index(MouseButton::RIGHT); } mb->set_button_mask(_get_mouse_button_state(mb->get_button_index(), event.xbutton.type)); mb->set_position(Vector2(event.xbutton.x, event.xbutton.y)); @@ -2778,15 +3498,15 @@ void DisplayServerX11::process_events() { if (diff < 400 && Vector2(last_click_pos).distance_to(Vector2(event.xbutton.x, event.xbutton.y)) < 5) { last_click_ms = 0; last_click_pos = Point2i(-100, -100); - last_click_button_index = -1; - mb->set_doubleclick(true); + last_click_button_index = MouseButton::NONE; + mb->set_double_click(true); } - } else if (mb->get_button_index() < 4 || mb->get_button_index() > 7) { + } else if (mb->get_button_index() < MouseButton::WHEEL_UP || mb->get_button_index() > MouseButton::WHEEL_RIGHT) { last_click_button_index = mb->get_button_index(); } - if (!mb->is_doubleclick()) { + if (!mb->is_double_click()) { last_click_ms += diff; last_click_pos = Point2i(event.xbutton.x, event.xbutton.y); } @@ -2799,9 +3519,9 @@ void DisplayServerX11::process_events() { // Note: This is needed for drag & drop to work between windows, // because the engine expects events to keep being processed // on the same window dragging started. - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - const WindowData &wd_other = E->get(); - WindowID window_id_other = E->key(); + for (const KeyValue<WindowID, WindowData> &E : windows) { + const WindowData &wd_other = E.value; + WindowID window_id_other = E.key; if (wd_other.focused) { if (window_id_other != window_id) { int x, y; @@ -2811,7 +3531,7 @@ void DisplayServerX11::process_events() { mb->set_window_id(window_id_other); mb->set_position(Vector2(x, y)); mb->set_global_position(mb->get_position()); - Input::get_singleton()->accumulate_input_event(mb); + Input::get_singleton()->parse_input_event(mb); } break; } @@ -2819,7 +3539,7 @@ void DisplayServerX11::process_events() { } } - Input::get_singleton()->accumulate_input_event(mb); + Input::get_singleton()->parse_input_event(mb); } break; case MotionNotify: { @@ -2834,11 +3554,11 @@ void DisplayServerX11::process_events() { break; } - if (XPending(x11_display) > 0) { - XEvent tevent; - XPeekEvent(x11_display, &tevent); - if (tevent.type == MotionNotify) { - XNextEvent(x11_display, &event); + if (event_index + 1 < events.size()) { + const XEvent &next_event = events[event_index + 1]; + if (next_event.type == MotionNotify) { + ++event_index; + event = next_event; } else { break; } @@ -2909,18 +3629,18 @@ void DisplayServerX11::process_events() { } Ref<InputEventMouseMotion> mm; - mm.instance(); + mm.instantiate(); mm->set_window_id(window_id); if (xi.pressure_supported) { mm->set_pressure(xi.pressure); } else { - mm->set_pressure((mouse_get_button_state() & (1 << (BUTTON_LEFT - 1))) ? 1.0f : 0.0f); + mm->set_pressure(bool(mouse_get_button_state() & MouseButton::MASK_LEFT) ? 1.0f : 0.0f); } mm->set_tilt(xi.tilt); _get_key_modifier_state(event.xmotion.state, mm); - mm->set_button_mask(mouse_get_button_state()); + mm->set_button_mask((MouseButton)mouse_get_button_state()); mm->set_position(pos); mm->set_global_position(pos); Input::get_singleton()->set_mouse_position(pos); @@ -2935,15 +3655,15 @@ void DisplayServerX11::process_events() { // this is so that the relative motion doesn't get messed up // after we regain focus. if (focused) { - Input::get_singleton()->accumulate_input_event(mm); + Input::get_singleton()->parse_input_event(mm); } else { // Propagate the event to the focused window, // because it's received only on the topmost window. // Note: This is needed for drag & drop to work between windows, // because the engine expects events to keep being processed // on the same window dragging started. - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - const WindowData &wd_other = E->get(); + for (const KeyValue<WindowID, WindowData> &E : windows) { + const WindowData &wd_other = E.value; if (wd_other.focused) { int x, y; Window child; @@ -2951,11 +3671,11 @@ void DisplayServerX11::process_events() { Point2i pos_focused(x, y); - mm->set_window_id(E->key()); + mm->set_window_id(E.key); mm->set_position(pos_focused); mm->set_global_position(pos_focused); mm->set_speed(Input::get_singleton()->get_last_mouse_speed()); - Input::get_singleton()->accumulate_input_event(mm); + Input::get_singleton()->parse_input_event(mm); break; } @@ -2965,71 +3685,18 @@ void DisplayServerX11::process_events() { } break; case KeyPress: case KeyRelease: { +#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED + if (event.type == KeyPress) { + DEBUG_LOG_X11("[%u] KeyPress window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time); + } else { + DEBUG_LOG_X11("[%u] KeyRelease window=%lu (%u), keycode=%u, time=%lu \n", frame, event.xkey.window, window_id, event.xkey.keycode, event.xkey.time); + } +#endif last_timestamp = event.xkey.time; // key event is a little complex, so // it will be handled in its own function. - _handle_key_event(window_id, (XKeyEvent *)&event); - } break; - case SelectionRequest: { - XSelectionRequestEvent *req; - XEvent e, respond; - e = event; - - req = &(e.xselectionrequest); - if (req->target == XInternAtom(x11_display, "UTF8_STRING", 0) || - req->target == XInternAtom(x11_display, "COMPOUND_TEXT", 0) || - req->target == XInternAtom(x11_display, "TEXT", 0) || - req->target == XA_STRING || - req->target == XInternAtom(x11_display, "text/plain;charset=utf-8", 0) || - req->target == XInternAtom(x11_display, "text/plain", 0)) { - CharString clip = clipboard_get().utf8(); - XChangeProperty(x11_display, - req->requestor, - req->property, - req->target, - 8, - PropModeReplace, - (unsigned char *)clip.get_data(), - clip.length()); - respond.xselection.property = req->property; - } else if (req->target == XInternAtom(x11_display, "TARGETS", 0)) { - Atom data[7]; - data[0] = XInternAtom(x11_display, "TARGETS", 0); - data[1] = XInternAtom(x11_display, "UTF8_STRING", 0); - data[2] = XInternAtom(x11_display, "COMPOUND_TEXT", 0); - data[3] = XInternAtom(x11_display, "TEXT", 0); - data[4] = XA_STRING; - data[5] = XInternAtom(x11_display, "text/plain;charset=utf-8", 0); - data[6] = XInternAtom(x11_display, "text/plain", 0); - - XChangeProperty(x11_display, - req->requestor, - req->property, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char *)&data, - sizeof(data) / sizeof(data[0])); - respond.xselection.property = req->property; - - } else { - char *targetname = XGetAtomName(x11_display, req->target); - printf("No Target '%s'\n", targetname); - if (targetname) { - XFree(targetname); - } - respond.xselection.property = None; - } - - respond.xselection.type = SelectionNotify; - respond.xselection.display = req->display; - respond.xselection.requestor = req->requestor; - respond.xselection.selection = req->selection; - respond.xselection.target = req->target; - respond.xselection.time = req->time; - XSendEvent(x11_display, req->requestor, True, NoEventMask, &respond); - XFlush(x11_display); + _handle_key_event(window_id, &event.xkey, events, event_index); } break; case SelectionNotify: @@ -3039,7 +3706,7 @@ void DisplayServerX11::process_events() { Vector<String> files = String((char *)p.data).split("\n", false); for (int i = 0; i < files.size(); i++) { - files.write[i] = files[i].replace("file://", "").http_unescape().strip_edges(); + files.write[i] = files[i].replace("file://", "").uri_decode().strip_edges(); } if (!windows[window_id].drop_files_callback.is_null()) { @@ -3148,16 +3815,27 @@ void DisplayServerX11::process_events() { */ } - Input::get_singleton()->flush_accumulated_events(); + Input::get_singleton()->flush_buffered_events(); } void DisplayServerX11::release_rendering_thread() { +#if defined(GLES3_ENABLED) +// gl_manager->release_current(); +#endif } void DisplayServerX11::make_rendering_thread() { +#if defined(GLES3_ENABLED) +// gl_manager->make_current(); +#endif } void DisplayServerX11::swap_buffers() { +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->swap_buffers(); + } +#endif } void DisplayServerX11::_update_context(WindowData &wd) { @@ -3202,8 +3880,8 @@ void DisplayServerX11::set_context(Context p_context) { context = p_context; - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { - _update_context(E->get()); + for (KeyValue<WindowID, WindowData> &E : windows) { + _update_context(E.value); } } @@ -3280,7 +3958,9 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) { pr += 4; } - XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); + if (net_wm_icon != None) { + XChangeProperty(x11_display, wd.x11_window, net_wm_icon, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)pd.ptr(), pd.size()); + } if (!g_set_icon_error) { break; @@ -3294,30 +3974,61 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) { XSetErrorHandler(oldHandler); } +void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + if (context_vulkan) { + context_vulkan->set_vsync_mode(p_window, p_vsync_mode); + } +#endif + +#if defined(GLES3_ENABLED) + if (gl_manager) { + gl_manager->set_use_vsync(p_vsync_mode == DisplayServer::VSYNC_ENABLED); + } +#endif +} + +DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_window) const { + _THREAD_SAFE_METHOD_ +#if defined(VULKAN_ENABLED) + if (context_vulkan) { + return context_vulkan->get_vsync_mode(p_window); + } +#endif +#if defined(GLES3_ENABLED) + if (gl_manager) { + return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; + } +#endif + return DisplayServer::VSYNC_ENABLED; +} + Vector<String> DisplayServerX11::get_rendering_drivers_func() { Vector<String> drivers; #ifdef VULKAN_ENABLED drivers.push_back("vulkan"); #endif -#ifdef OPENGL_ENABLED - drivers.push_back("opengl"); +#ifdef GLES3_ENABLED + drivers.push_back("opengl3"); #endif return drivers; } -DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); +DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { + DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_resolution, r_error)); if (r_error != OK) { - ds->alert("Your video card driver does not support any of the supported Vulkan versions.\n" - "Please update your drivers or if you have a very old or integrated GPU upgrade it.", + OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan or OpenGL versions.\n" + "Please update your drivers or if you have a very old or integrated GPU, upgrade it.\n" + "If you have updated your graphics drivers recently, try rebooting.", "Unable to initialize Video driver"); } return ds; } -DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { +DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect) { //Create window long visualMask = VisualScreenMask; @@ -3373,7 +4084,9 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u { const long pid = OS::get_singleton()->get_process_id(); Atom net_wm_pid = XInternAtom(x11_display, "_NET_WM_PID", False); - XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); + if (net_wm_pid != None) { + XChangeProperty(x11_display, wd.x11_window, net_wm_pid, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); + } } long im_event_mask = 0; @@ -3383,18 +4096,18 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u XSetWindowAttributes new_attr; new_attr.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | - ButtonReleaseMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask | - Button1MotionMask | - Button2MotionMask | Button3MotionMask | - Button4MotionMask | Button5MotionMask | - ButtonMotionMask | KeymapStateMask | - ExposureMask | VisibilityChangeMask | - StructureNotifyMask | - SubstructureNotifyMask | SubstructureRedirectMask | - FocusChangeMask | PropertyChangeMask | - ColormapChangeMask | OwnerGrabButtonMask | - im_event_mask; + ButtonReleaseMask | EnterWindowMask | + LeaveWindowMask | PointerMotionMask | + Button1MotionMask | + Button2MotionMask | Button3MotionMask | + Button4MotionMask | Button5MotionMask | + ButtonMotionMask | KeymapStateMask | + ExposureMask | VisibilityChangeMask | + StructureNotifyMask | + SubstructureNotifyMask | SubstructureRedirectMask | + FocusChangeMask | PropertyChangeMask | + ColormapChangeMask | OwnerGrabButtonMask | + im_event_mask; XChangeWindowAttributes(x11_display, wd.x11_window, CWEventMask, &new_attr); @@ -3421,9 +4134,15 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u /* set the titlebar name */ XStoreName(x11_display, wd.x11_window, "Godot"); XSetWMProtocols(x11_display, wd.x11_window, &wm_delete, 1); - XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1); + if (xdnd_aware != None) { + XChangeProperty(x11_display, wd.x11_window, xdnd_aware, XA_ATOM, 32, PropModeReplace, (unsigned char *)&xdnd_version, 1); + } if (xim && xim_style) { + // Block events polling while changing input focus + // because it triggers some event polling internally. + MutexLock mutex_lock(events_mutex); + wd.xic = XCreateIC(xim, XNInputStyle, xim_style, XNClientWindow, wd.x11_window, XNFocusWindow, wd.x11_window, (char *)nullptr); if (XGetICValues(wd.xic, XNFilterEvents, &im_event_mask, nullptr) != nullptr) { WARN_PRINT("XGetICValues couldn't obtain XNFilterEvents value"); @@ -3448,30 +4167,41 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u hints.flags = 2; hints.decorations = 0; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); - XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + if (property != None) { + XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + } } if (wd.menu_type) { // Set Utility type to disable fade animations. Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False); Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - - XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + if (wt_atom != None && type_atom != None) { + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + } } else { Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False); Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + if (wt_atom != None && type_atom != None) { + XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); + } } _update_size_hints(id); #if defined(VULKAN_ENABLED) if (context_vulkan) { - Error err = context_vulkan->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); + Error err = context_vulkan->window_create(id, p_vsync_mode, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window"); } #endif +#ifdef GLES3_ENABLED + if (gl_manager) { + Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); + ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window"); + } +#endif //set_class_hint(x11_display, wd.x11_window); XFlush(x11_display); @@ -3495,8 +4225,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u wd.position.y = xwa.y; wd.size.width = xwa.width; wd.size.height = xwa.height; - - print_line("DisplayServer::_create_window " + itos(id) + " want rect: " + p_rect + " got rect " + Rect2i(xwa.x, xwa.y, xwa.width, xwa.height)); } //set cursor @@ -3507,7 +4235,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u return id; } -DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { +DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { Input::get_singleton()->set_event_dispatch_function(_dispatch_input_events); r_error = OK; @@ -3520,12 +4248,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode img[i] = nullptr; } - last_button_state = 0; - xmbstring = nullptr; last_click_ms = 0; - last_click_button_index = -1; + last_click_button_index = MouseButton::NONE; last_click_pos = Point2i(-100, -100); last_timestamp = 0; @@ -3600,8 +4326,8 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } if (!_refresh_device_info()) { - alert("Your system does not support XInput 2.\n" - "Please upgrade your distribution.", + OS::get_singleton()->alert("Your system does not support XInput 2.\n" + "Please upgrade your distribution.", "Unable to initialize XInput"); r_error = ERR_UNAVAILABLE; return; @@ -3657,14 +4383,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode xdnd_selection = XInternAtom(x11_display, "XdndSelection", False); //!!!!!!!!!!!!!!!!!!!!!!!!!! - //TODO - do Vulkan and GLES2 support checks, driver selection and fallback + //TODO - do Vulkan and OpenGL support checks, driver selection and fallback rendering_driver = p_rendering_driver; -#ifndef _MSC_VER -#warning Forcing vulkan rendering driver because OpenGL not implemented yet -#endif - rendering_driver = "vulkan"; - + bool driver_found = false; #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { context_vulkan = memnew(VulkanContextX11); @@ -3674,11 +4396,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode r_error = ERR_CANT_CREATE; ERR_FAIL_MSG("Could not initialize Vulkan"); } + driver_found = true; } #endif - // Init context and rendering device -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl_es") { + // Initialize context and rendering device. +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { if (getenv("DRI_PRIME") == nullptr) { int use_prime = -1; @@ -3692,7 +4415,10 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode use_prime = 0; } - if (getenv("LD_LIBRARY_PATH")) { + // Some tools use fake libGL libraries and have them override the real one using + // LD_LIBRARY_PATH, so we skip them. *But* Steam also sets LD_LIBRARY_PATH for its + // runtime and includes system `/lib` and `/lib64`... so ignore Steam. + if (use_prime == -1 && getenv("LD_LIBRARY_PATH") && !getenv("STEAM_RUNTIME_LIBRARY_PATH")) { String ld_library_path(getenv("LD_LIBRARY_PATH")); Vector<String> libraries = ld_library_path.split(":"); @@ -3717,32 +4443,45 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } - ContextGL_X11::ContextType opengl_api_type = ContextGL_X11::GLES_2_0_COMPATIBLE; + GLManager_X11::ContextType opengl_api_type = GLManager_X11::GLES_3_0_COMPATIBLE; - context_gles2 = memnew(ContextGL_X11(x11_display, x11_window, current_videomode, opengl_api_type)); + gl_manager = memnew(GLManager_X11(p_resolution, opengl_api_type)); - if (context_gles2->initialize() != OK) { - memdelete(context_gles2); - context_gles2 = nullptr; - ERR_FAIL_V(ERR_UNAVAILABLE); + if (gl_manager->initialize() != OK) { + memdelete(gl_manager); + gl_manager = nullptr; + r_error = ERR_UNAVAILABLE; + return; } + driver_found = true; - context_gles2->set_use_vsync(current_videomode.use_vsync); + // gl_manager->set_use_vsync(current_videomode.use_vsync); - if (RasterizerGLES2::is_viable() == OK) { - RasterizerGLES2::register_config(); - RasterizerGLES2::make_current(); + if (true) { + // if (RasterizerGLES3::is_viable() == OK) { + // RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { - memdelete(context_gles2); - context_gles2 = nullptr; - ERR_FAIL_V(ERR_UNAVAILABLE); + memdelete(gl_manager); + gl_manager = nullptr; + r_error = ERR_UNAVAILABLE; + return; } } #endif + if (!driver_found) { + r_error = ERR_UNAVAILABLE; + ERR_FAIL_MSG("Video driver not found"); + } + Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); - WindowID main_window = _create_window(p_mode, p_flags, Rect2i(window_position, p_resolution)); + WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution)); + if (main_window == INVALID_WINDOW_ID) { + r_error = ERR_CANT_CREATE; + return; + } for (int i = 0; i < WINDOW_FLAG_MAX; i++) { if (p_flags & (1 << i)) { window_set_flag(WindowFlags(i), true, main_window); @@ -3750,24 +4489,16 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } show_window(main_window); -//create RenderingDevice if used #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { //temporary rendering_device_vulkan = memnew(RenderingDeviceVulkan); rendering_device_vulkan->initialize(context_vulkan); - RasterizerRD::make_current(); + RendererCompositorRD::make_current(); } #endif - /* - rendering_server = memnew(RenderingServerRaster); - if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { - rendering_server = memnew(RenderingServerWrapMT(rendering_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); - } - */ - { //set all event master mask XIEventMask all_master_event_mask; @@ -3780,15 +4511,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode XISelectEvents(x11_display, DefaultRootWindow(x11_display), &all_master_event_mask, 1); } - // Disabled by now since grabbing also blocks mouse events - // (they are received as extended events instead of standard events) - /*XIClearMask(xi.touch_event_mask.mask, XI_TouchOwnership); - - // Grab touch devices to avoid OS gesture interference - for (int i = 0; i < xi.touch_devices.size(); ++i) { - XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask); - }*/ - cursor_size = XcursorGetDefaultSize(x11_display); cursor_theme = XcursorGetTheme(x11_display); @@ -3926,25 +4648,47 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } + events_thread.start(_poll_events_thread, this); + _update_real_mouse_position(windows[MAIN_WINDOW_ID]); +#ifdef DBUS_ENABLED + screensaver = memnew(FreeDesktopScreenSaver); + screen_set_keep_on(GLOBAL_DEF("display/window/energy_saving/keep_screen_on", true)); +#endif + r_error = OK; } DisplayServerX11::~DisplayServerX11() { + // Send owned clipboard data to clipboard manager before exit. + Window x11_main_window = windows[MAIN_WINDOW_ID].x11_window; + _clipboard_transfer_ownership(XA_PRIMARY, x11_main_window); + _clipboard_transfer_ownership(XInternAtom(x11_display, "CLIPBOARD", 0), x11_main_window); + + events_thread_done.set(); + events_thread.wait_to_finish(); + //destroy all windows - for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { + for (KeyValue<WindowID, WindowData> &E : windows) { #ifdef VULKAN_ENABLED if (rendering_driver == "vulkan") { - context_vulkan->window_destroy(E->key()); + context_vulkan->window_destroy(E.key); + } +#endif +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { + gl_manager->window_destroy(E.key); } #endif - if (E->get().xic) { - XDestroyIC(E->get().xic); + WindowData &wd = E.value; + if (wd.xic) { + XDestroyIC(wd.xic); + wd.xic = nullptr; } - XUnmapWindow(x11_display, E->get().x11_window); - XDestroyWindow(x11_display, E->get().x11_window); + XUnmapWindow(x11_display, wd.x11_window); + XDestroyWindow(x11_display, wd.x11_window); } //destroy drivers @@ -3961,6 +4705,13 @@ DisplayServerX11::~DisplayServerX11() { } #endif +#ifdef GLES3_ENABLED + if (gl_manager) { + memdelete(gl_manager); + gl_manager = nullptr; + } +#endif + if (xrandr_handle) { dlclose(xrandr_handle); } @@ -3982,6 +4733,10 @@ DisplayServerX11::~DisplayServerX11() { if (xmbstring) { memfree(xmbstring); } + +#ifdef DBUS_ENABLED + memdelete(screensaver); +#endif } void DisplayServerX11::register_x11_driver() { diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index e894cf515c..3587d587d6 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -31,22 +31,25 @@ #ifndef DISPLAY_SERVER_X11_H #define DISPLAY_SERVER_X11_H +#include "drivers/gles3/rasterizer_platforms.h" + #ifdef X11_ENABLED #include "servers/display_server.h" #include "core/input/input.h" +#include "core/templates/local_vector.h" #include "drivers/alsa/audio_driver_alsa.h" #include "drivers/alsamidi/midi_driver_alsamidi.h" #include "drivers/pulseaudio/audio_driver_pulseaudio.h" #include "drivers/unix/os_unix.h" #include "joypad_linux.h" #include "servers/audio_server.h" -#include "servers/rendering/rasterizer.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" -#if defined(OPENGL_ENABLED) -#include "context_gl_x11.h" +#if defined(GLES3_ENABLED) +#include "gl_manager_x11.h" #endif #if defined(VULKAN_ENABLED) @@ -54,33 +57,28 @@ #include "platform/linuxbsd/vulkan_context_x11.h" #endif +#if defined(DBUS_ENABLED) +#include "freedesktop_screensaver.h" +#endif + #include <X11/Xcursor/Xcursor.h> #include <X11/Xlib.h> #include <X11/extensions/XInput2.h> #include <X11/extensions/Xrandr.h> #include <X11/keysym.h> -// Hints for X11 fullscreen -typedef struct { - unsigned long flags; - unsigned long functions; - unsigned long decorations; - long inputMode; - unsigned long status; -} Hints; - typedef struct _xrr_monitor_info { Atom name; - Bool primary; - Bool automatic; - int noutput; - int x; - int y; - int width; - int height; - int mwidth; - int mheight; - RROutput *outputs; + Bool primary = false; + Bool automatic = false; + int noutput = 0; + int x = 0; + int y = 0; + int width = 0; + int height = 0; + int mwidth = 0; + int mheight = 0; + RROutput *outputs = nullptr; } xrr_monitor_info; #undef CursorShape @@ -103,12 +101,17 @@ class DisplayServerX11 : public DisplayServer { Atom requested; int xdnd_version; -#if defined(OPENGL_ENABLED) - ContextGL_X11 *context_gles2; +#if defined(GLES3_ENABLED) + GLManager_X11 *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) - VulkanContextX11 *context_vulkan; - RenderingDeviceVulkan *rendering_device_vulkan; + VulkanContextX11 *context_vulkan = nullptr; + RenderingDeviceVulkan *rendering_device_vulkan = nullptr; +#endif + +#if defined(DBUS_ENABLED) + FreeDesktopScreenSaver *screensaver; + bool keep_screen_on = false; #endif struct WindowData { @@ -151,9 +154,10 @@ class DisplayServerX11 : public DisplayServer { Map<WindowID, WindowData> windows; WindowID window_id_counter = MAIN_WINDOW_ID; - WindowID _create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect); + WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect); String internal_clipboard; + String internal_clipboard_primary; Window xdnd_source_window; ::Display *x11_display; char *xmbstring; @@ -169,8 +173,8 @@ class DisplayServerX11 : public DisplayServer { bool last_mouse_pos_valid; Point2i last_click_pos; uint64_t last_click_ms; - int last_click_button_index; - uint32_t last_button_state; + MouseButton last_click_button_index = MouseButton::NONE; + MouseButton last_button_state = MouseButton::NONE; bool app_focused = false; uint64_t time_since_no_focus = 0; @@ -195,14 +199,23 @@ class DisplayServerX11 : public DisplayServer { bool _refresh_device_info(); - unsigned int _get_mouse_button_state(unsigned int p_x11_button, int p_x11_type); + Rect2i _screen_get_rect(int p_screen) const; + + MouseButton _get_mouse_button_state(MouseButton p_x11_button, int p_x11_type); void _get_key_modifier_state(unsigned int p_x11_state, Ref<InputEventWithModifiers> state); void _flush_mouse_motion(); MouseMode mouse_mode; Point2i center; - void _handle_key_event(WindowID p_window, XKeyEvent *p_event, bool p_echo = false); + void _handle_key_event(WindowID p_window, XKeyEvent *p_event, LocalVector<XEvent> &p_events, uint32_t &p_event_index, bool p_echo = false); + + Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const; + void _handle_selection_request_event(XSelectionRequestEvent *p_event) const; + + String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const; + String _clipboard_get(Atom p_source, Window x11_window) const; + void _clipboard_transfer_ownership(Atom p_source, Window x11_window) const; //bool minimized; //bool window_has_focus; @@ -252,117 +265,141 @@ class DisplayServerX11 : public DisplayServer { static void _dispatch_input_events(const Ref<InputEvent> &p_event); void _dispatch_input_event(const Ref<InputEvent> &p_event); + mutable Mutex events_mutex; + Thread events_thread; + SafeFlag events_thread_done; + LocalVector<XEvent> polled_events; + static void _poll_events_thread(void *ud); + bool _wait_for_events() const; + void _poll_events(); + void _check_pending_events(LocalVector<XEvent> &r_events); + + static Bool _predicate_all_events(Display *display, XEvent *event, XPointer arg); + static Bool _predicate_clipboard_selection(Display *display, XEvent *event, XPointer arg); + static Bool _predicate_clipboard_incr(Display *display, XEvent *event, XPointer arg); + static Bool _predicate_clipboard_save_targets(Display *display, XEvent *event, XPointer arg); + protected: void _window_changed(XEvent *event); public: - virtual bool has_feature(Feature p_feature) const; - virtual String get_name() const; - - virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); - - virtual void mouse_set_mode(MouseMode p_mode); - virtual MouseMode mouse_get_mode() const; - - virtual void mouse_warp_to_position(const Point2i &p_to); - virtual Point2i mouse_get_position() const; - virtual Point2i mouse_get_absolute_position() const; - virtual int mouse_get_button_state() const; - - virtual void clipboard_set(const String &p_text); - virtual String clipboard_get() const; + virtual bool has_feature(Feature p_feature) const override; + virtual String get_name() const override; + + virtual void mouse_set_mode(MouseMode p_mode) override; + virtual MouseMode mouse_get_mode() const override; + + virtual void mouse_warp_to_position(const Point2i &p_to) override; + virtual Point2i mouse_get_position() const override; + virtual Point2i mouse_get_absolute_position() const override; + virtual MouseButton mouse_get_button_state() const override; + + virtual void clipboard_set(const String &p_text) override; + virtual String clipboard_get() const override; + virtual void clipboard_set_primary(const String &p_text) override; + virtual String clipboard_get_primary() const override; + + virtual int get_screen_count() 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 bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const override; + +#if defined(DBUS_ENABLED) + virtual void screen_set_keep_on(bool p_enable) override; + virtual bool screen_is_kept_on() const override; +#endif - virtual int get_screen_count() const; - virtual Point2i screen_get_position(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual Size2i screen_get_size(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual Rect2i screen_get_usable_rect(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual int screen_get_dpi(int p_screen = SCREEN_OF_MAIN_WINDOW) const; - virtual bool screen_is_touchscreen(int p_screen = SCREEN_OF_MAIN_WINDOW) const; + virtual Vector<DisplayServer::WindowID> get_window_list() const override; - virtual Vector<DisplayServer::WindowID> get_window_list() const; + virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()) override; + virtual void show_window(WindowID p_id) override; + virtual void delete_sub_window(WindowID p_id) override; - virtual WindowID create_sub_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i()); - virtual void show_window(WindowID p_id); - virtual void delete_sub_window(WindowID p_id); + virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override; - virtual WindowID get_window_at_screen_position(const Point2i &p_position) const; + virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID) override; + virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void window_attach_instance_id(ObjectID p_instance, WindowID p_window = MAIN_WINDOW_ID); - virtual ObjectID window_get_attached_instance_id(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID) override; - virtual void window_set_title(const String &p_title, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_mouse_passthrough(const Vector<Vector2> &p_region, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID) override; - virtual void window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_window_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_input_event_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_input_text_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_drop_files_callback(const Callable &p_callable, WindowID p_window = MAIN_WINDOW_ID); + virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID) override; - virtual int window_get_current_screen(WindowID p_window = MAIN_WINDOW_ID) const; - virtual void window_set_current_screen(int p_screen, WindowID p_window = MAIN_WINDOW_ID); + virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID) override; - virtual Point2i window_get_position(WindowID p_window = MAIN_WINDOW_ID) const; - virtual void window_set_position(const Point2i &p_position, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id) override; - virtual void window_set_max_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID); - virtual Size2i window_get_max_size(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_transient(WindowID p_window, WindowID p_parent) override; - virtual void window_set_transient(WindowID p_window, WindowID p_parent); + virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void window_set_min_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID); - virtual Size2i window_get_min_size(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID) override; + virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const override; + virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void window_set_size(const Size2i p_size, WindowID p_window = MAIN_WINDOW_ID); - virtual Size2i window_get_size(WindowID p_window = MAIN_WINDOW_ID) const; - virtual Size2i window_get_real_size(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void window_set_mode(WindowMode p_mode, WindowID p_window = MAIN_WINDOW_ID); - virtual WindowMode window_get_mode(WindowID p_window = MAIN_WINDOW_ID) const; + virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual bool window_is_maximize_allowed(WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID) override; + virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const override; - virtual void window_set_flag(WindowFlags p_flag, bool p_enabled, WindowID p_window = MAIN_WINDOW_ID); - virtual bool window_get_flag(WindowFlags p_flag, WindowID p_window = MAIN_WINDOW_ID) const; + virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID) override; - virtual void window_request_attention(WindowID p_window = MAIN_WINDOW_ID); + virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override; - virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID); + virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override; - virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const; + virtual bool can_any_window_draw() const override; - virtual bool can_any_window_draw() const; + virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID) override; + virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID) override; - virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID); - virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID); + virtual void window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window = MAIN_WINDOW_ID) override; + virtual DisplayServer::VSyncMode window_get_vsync_mode(WindowID p_vsync_mode) const override; - virtual void cursor_set_shape(CursorShape p_shape); - virtual CursorShape cursor_get_shape() const; - virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); + virtual void cursor_set_shape(CursorShape p_shape) override; + virtual CursorShape cursor_get_shape() const override; + virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) override; - virtual int keyboard_get_layout_count() const; - virtual int keyboard_get_current_layout() const; - virtual void keyboard_set_current_layout(int p_index); - virtual String keyboard_get_layout_language(int p_index) const; - virtual String keyboard_get_layout_name(int p_index) const; + virtual int keyboard_get_layout_count() const override; + virtual int keyboard_get_current_layout() const override; + virtual void keyboard_set_current_layout(int p_index) override; + virtual String keyboard_get_layout_language(int p_index) const override; + virtual String keyboard_get_layout_name(int p_index) const override; + virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const override; - virtual void process_events(); + virtual void process_events() override; - virtual void release_rendering_thread(); - virtual void make_rendering_thread(); - virtual void swap_buffers(); + virtual void release_rendering_thread() override; + virtual void make_rendering_thread() override; + virtual void swap_buffers() override; - virtual void set_context(Context p_context); + virtual void set_context(Context p_context) override; - virtual void set_native_icon(const String &p_filename); - virtual void set_icon(const Ref<Image> &p_icon); + virtual void set_native_icon(const String &p_filename) override; + virtual void set_icon(const Ref<Image> &p_icon) override; - static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + static DisplayServer *create_func(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); static Vector<String> get_rendering_drivers_func(); static void register_x11_driver(); - DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); + DisplayServerX11(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error); ~DisplayServerX11(); }; diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 86ea95c563..965a38ef4e 100644 --- a/platform/linuxbsd/export/export.cpp +++ b/platform/linuxbsd/export/export.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,7 @@ #include "export.h" -#include "core/os/file_access.h" +#include "core/io/file_access.h" #include "editor/editor_export.h" #include "platform/linuxbsd/logo.gen.h" #include "scene/resources/texture.h" @@ -39,11 +39,11 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start, void register_linuxbsd_exporter() { Ref<EditorExportPlatformPC> platform; - platform.instance(); + platform.instantiate(); Ref<Image> img = memnew(Image(_linuxbsd_logo)); Ref<ImageTexture> logo; - logo.instance(); + logo.instantiate(); logo->create_from_image(img); platform->set_logo(logo); platform->set_name("Linux/X11"); @@ -53,7 +53,7 @@ void register_linuxbsd_exporter() { platform->set_debug_32("linux_x11_32_debug"); platform->set_release_64("linux_x11_64_release"); platform->set_debug_64("linux_x11_64_debug"); - platform->set_os_name("X11"); + platform->set_os_name("LinuxBSD"); platform->set_chmod_flags(0755); platform->set_fixup_embedded_pck_func(&fixup_embedded_pck); diff --git a/platform/linuxbsd/export/export.h b/platform/linuxbsd/export/export.h index 5ee81f485e..61e96aa2f6 100644 --- a/platform/linuxbsd/export/export.h +++ b/platform/linuxbsd/export/export.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/linuxbsd/freedesktop_screensaver.cpp b/platform/linuxbsd/freedesktop_screensaver.cpp new file mode 100644 index 0000000000..3973d43d49 --- /dev/null +++ b/platform/linuxbsd/freedesktop_screensaver.cpp @@ -0,0 +1,129 @@ +/*************************************************************************/ +/* freedesktop_screensaver.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "freedesktop_screensaver.h" + +#ifdef DBUS_ENABLED + +#include "core/config/project_settings.h" + +#include <dbus/dbus.h> + +#define BUS_OBJECT_NAME "org.freedesktop.ScreenSaver" +#define BUS_OBJECT_PATH "/org/freedesktop/ScreenSaver" +#define BUS_INTERFACE "org.freedesktop.ScreenSaver" + +void FreeDesktopScreenSaver::inhibit() { + if (unsupported) { + return; + } + + DBusError error; + dbus_error_init(&error); + + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + unsupported = true; + return; + } + + String app_name_string = ProjectSettings::get_singleton()->get("application/config/name"); + CharString app_name_utf8 = app_name_string.utf8(); + const char *app_name = app_name_string.is_empty() ? "Godot Engine" : app_name_utf8.get_data(); + + const char *reason = "Running Godot Engine project"; + + DBusMessage *message = dbus_message_new_method_call( + BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE, + "Inhibit"); + dbus_message_append_args( + message, + DBUS_TYPE_STRING, &app_name, + DBUS_TYPE_STRING, &reason, + DBUS_TYPE_INVALID); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error); + dbus_message_unref(message); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + dbus_connection_unref(bus); + unsupported = false; + return; + } + + DBusMessageIter reply_iter; + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &cookie); + print_verbose("FreeDesktopScreenSaver: Acquired screensaver inhibition cookie: " + uitos(cookie)); + + dbus_message_unref(reply); + dbus_connection_unref(bus); +} + +void FreeDesktopScreenSaver::uninhibit() { + if (unsupported) { + return; + } + + DBusError error; + dbus_error_init(&error); + + DBusConnection *bus = dbus_bus_get(DBUS_BUS_SESSION, &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + unsupported = true; + return; + } + + DBusMessage *message = dbus_message_new_method_call( + BUS_OBJECT_NAME, BUS_OBJECT_PATH, BUS_INTERFACE, + "UnInhibit"); + dbus_message_append_args( + message, + DBUS_TYPE_UINT32, &cookie, + DBUS_TYPE_INVALID); + + DBusMessage *reply = dbus_connection_send_with_reply_and_block(bus, message, 50, &error); + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + dbus_connection_unref(bus); + unsupported = true; + return; + } + + print_verbose("FreeDesktopScreenSaver: Released screensaver inhibition cookie: " + uitos(cookie)); + + dbus_message_unref(message); + dbus_message_unref(reply); + dbus_connection_unref(bus); +} + +#endif // DBUS_ENABLED diff --git a/platform/linuxbsd/context_gl_x11.h b/platform/linuxbsd/freedesktop_screensaver.h index 7aed280c98..f27e60fce4 100644 --- a/platform/linuxbsd/context_gl_x11.h +++ b/platform/linuxbsd/freedesktop_screensaver.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* context_gl_x11.h */ +/* freedesktop_screensaver.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -28,53 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONTEXT_GL_X11_H -#define CONTEXT_GL_X11_H +#ifdef DBUS_ENABLED -#ifdef X11_ENABLED - -#if defined(OPENGL_ENABLED) - -#include "core/os/os.h" -#include <X11/Xlib.h> -#include <X11/extensions/Xrender.h> - -struct ContextGL_X11_Private; - -class ContextGL_X11 { -public: - enum ContextType { - GLES_2_0_COMPATIBLE, - }; +#include <dbus/dbus.h> +#include <stdint.h> +class FreeDesktopScreenSaver { private: - ContextGL_X11_Private *p; - OS::VideoMode default_video_mode; - ::Display *x11_display; - ::Window &x11_window; - bool double_buffer; - bool direct_render; - int glx_minor, glx_major; - bool use_vsync; - ContextType context_type; + uint32_t cookie = 0; + bool unsupported = false; public: - void release_current(); - void make_current(); - void swap_buffers(); - int get_window_width(); - int get_window_height(); - - Error initialize(); - - void set_use_vsync(bool p_use); - bool is_using_vsync() const; - - ContextGL_X11(::Display *p_x11_display, ::Window &p_x11_window, const OS::VideoMode &p_default_video_mode, ContextType p_context_type); - ~ContextGL_X11(); + FreeDesktopScreenSaver() {} + void inhibit(); + void uninhibit(); }; -#endif - -#endif -#endif +#endif // DBUS_ENABLED diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp new file mode 100644 index 0000000000..e069e92ee6 --- /dev/null +++ b/platform/linuxbsd/gl_manager_x11.cpp @@ -0,0 +1,384 @@ +/*************************************************************************/ +/* gl_manager_x11.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "gl_manager_x11.h" + +#ifdef X11_ENABLED +#if defined(GLES3_ENABLED) + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#define GLX_GLXEXT_PROTOTYPES +#include <GL/glx.h> +#include <GL/glxext.h> + +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 + +typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display *, GLXFBConfig, GLXContext, Bool, const int *); + +struct GLManager_X11_Private { + ::GLXContext glx_context; +}; + +GLManager_X11::GLDisplay::~GLDisplay() { + if (context) { + //release_current(); + glXDestroyContext(x11_display, context->glx_context); + memdelete(context); + context = nullptr; + } +} + +static bool ctxErrorOccurred = false; +static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) { + ctxErrorOccurred = true; + return 0; +} + +int GLManager_X11::_find_or_create_display(Display *p_x11_display) { + for (unsigned int n = 0; n < _displays.size(); n++) { + const GLDisplay &d = _displays[n]; + if (d.x11_display == p_x11_display) + return n; + } + + // create + GLDisplay d_temp; + d_temp.x11_display = p_x11_display; + _displays.push_back(d_temp); + int new_display_id = _displays.size() - 1; + + // create context + GLDisplay &d = _displays[new_display_id]; + + d.context = memnew(GLManager_X11_Private); + ; + d.context->glx_context = 0; + + //Error err = _create_context(d); + _create_context(d); + return new_display_id; +} + +Error GLManager_X11::_create_context(GLDisplay &gl_display) { + // some aliases + ::Display *x11_display = gl_display.x11_display; + + //const char *extensions = glXQueryExtensionsString(x11_display, DefaultScreen(x11_display)); + + GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB"); + + ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED); + + static int visual_attribs[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DOUBLEBUFFER, true, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DEPTH_SIZE, 24, + None + }; + + static int visual_attribs_layered[] = { + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_DOUBLEBUFFER, true, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None + }; + + int fbcount; + GLXFBConfig fbconfig = 0; + XVisualInfo *vi = nullptr; + + gl_display.x_swa.event_mask = StructureNotifyMask; + gl_display.x_swa.border_pixel = 0; + gl_display.x_valuemask = CWBorderPixel | CWColormap | CWEventMask; + + if (OS::get_singleton()->is_layered_allowed()) { + GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount); + ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); + + for (int i = 0; i < fbcount; i++) { + vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]); + if (!vi) + continue; + + XRenderPictFormat *pict_format = XRenderFindVisualFormat(x11_display, vi->visual); + if (!pict_format) { + XFree(vi); + vi = nullptr; + continue; + } + + fbconfig = fbc[i]; + if (pict_format->direct.alphaMask > 0) { + break; + } + } + XFree(fbc); + + ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED); + + gl_display.x_swa.background_pixmap = None; + gl_display.x_swa.background_pixel = 0; + gl_display.x_swa.border_pixmap = None; + gl_display.x_valuemask |= CWBackPixel; + + } else { + GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount); + ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED); + + vi = glXGetVisualFromFBConfig(x11_display, fbc[0]); + + fbconfig = fbc[0]; + XFree(fbc); + } + + int (*oldHandler)(Display *, XErrorEvent *) = XSetErrorHandler(&ctxErrorHandler); + + switch (context_type) { + case GLES_3_0_COMPATIBLE: { + static int context_attribs[] = { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*|GLX_CONTEXT_DEBUG_BIT_ARB*/, + None + }; + + gl_display.context->glx_context = glXCreateContextAttribsARB(x11_display, fbconfig, nullptr, true, context_attribs); + ERR_FAIL_COND_V(ctxErrorOccurred || !gl_display.context->glx_context, ERR_UNCONFIGURED); + } break; + } + + gl_display.x_swa.colormap = XCreateColormap(x11_display, RootWindow(x11_display, vi->screen), vi->visual, AllocNone); + + XSync(x11_display, False); + XSetErrorHandler(oldHandler); + + // make our own copy of the vi data + // for later creating windows using this display + if (vi) { + gl_display.x_vi = *vi; + } + + XFree(vi); + + return OK; +} + +Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { + // make sure vector is big enough... + // we can mirror the external vector, it is simpler + // to keep the IDs identical for fast lookup + if (p_window_id >= (int)_windows.size()) { + _windows.resize(p_window_id + 1); + } + + GLWindow &win = _windows[p_window_id]; + win.in_use = true; + win.window_id = p_window_id; + win.width = p_width; + win.height = p_height; + win.x11_window = p_window; + win.gldisplay_id = _find_or_create_display(p_display); + + // the display could be invalid .. check NYI + GLDisplay &gl_display = _displays[win.gldisplay_id]; + //const XVisualInfo &vi = gl_display.x_vi; + //XSetWindowAttributes &swa = gl_display.x_swa; + ::Display *x11_display = gl_display.x11_display; + ::Window &x11_window = win.x11_window; + + if (!glXMakeCurrent(x11_display, x11_window, gl_display.context->glx_context)) { + ERR_PRINT("glXMakeCurrent failed"); + } + + _internal_set_current_window(&win); + + return OK; +} + +void GLManager_X11::_internal_set_current_window(GLWindow *p_win) { + _current_window = p_win; + + // quick access to x info + _x_windisp.x11_window = _current_window->x11_window; + const GLDisplay &disp = get_current_display(); + _x_windisp.x11_display = disp.x11_display; +} + +void GLManager_X11::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) { + get_window(p_window_id).width = p_width; + get_window(p_window_id).height = p_height; +} + +void GLManager_X11::window_destroy(DisplayServer::WindowID p_window_id) { + GLWindow &win = get_window(p_window_id); + win.in_use = false; + + if (_current_window == &win) { + _current_window = nullptr; + _x_windisp.x11_display = nullptr; + _x_windisp.x11_window = -1; + } +} + +void GLManager_X11::release_current() { + if (!_current_window) + return; + glXMakeCurrent(_x_windisp.x11_display, None, nullptr); +} + +void GLManager_X11::window_make_current(DisplayServer::WindowID p_window_id) { + if (p_window_id == -1) + return; + + GLWindow &win = _windows[p_window_id]; + if (!win.in_use) + return; + + // noop + if (&win == _current_window) + return; + + const GLDisplay &disp = get_display(win.gldisplay_id); + + glXMakeCurrent(disp.x11_display, win.x11_window, disp.context->glx_context); + + _internal_set_current_window(&win); +} + +void GLManager_X11::make_current() { + if (!_current_window) + return; + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + const GLDisplay &disp = get_current_display(); + glXMakeCurrent(_x_windisp.x11_display, _x_windisp.x11_window, disp.context->glx_context); +} + +void GLManager_X11::swap_buffers() { + // NO NEED TO CALL SWAP BUFFERS for each window... + // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml + + if (!_current_window) + return; + if (!_current_window->in_use) { + WARN_PRINT("current window not in use!"); + return; + } + + // print_line("\tswap_buffers"); + + // only for debugging without drawing anything + // glClearColor(Math::randf(), 0, 1, 1); + //glClear(GL_COLOR_BUFFER_BIT); + + //const GLDisplay &disp = get_current_display(); + glXSwapBuffers(_x_windisp.x11_display, _x_windisp.x11_window); +} + +Error GLManager_X11::initialize() { + return OK; +} + +void GLManager_X11::set_use_vsync(bool p_use) { + static bool setup = false; + static PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT = nullptr; + static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalMESA = nullptr; + static PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI = nullptr; + + // force vsync in the editor for now, as a safety measure + bool is_editor = Engine::get_singleton()->is_editor_hint(); + if (is_editor) { + p_use = true; + } + + // we need an active window to get a display to set the vsync + if (!_current_window) + return; + const GLDisplay &disp = get_current_display(); + + if (!setup) { + setup = true; + String extensions = glXQueryExtensionsString(disp.x11_display, DefaultScreen(disp.x11_display)); + if (extensions.find("GLX_EXT_swap_control") != -1) + glXSwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalEXT"); + if (extensions.find("GLX_MESA_swap_control") != -1) + glXSwapIntervalMESA = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalMESA"); + if (extensions.find("GLX_SGI_swap_control") != -1) + glXSwapIntervalSGI = (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte *)"glXSwapIntervalSGI"); + } + int val = p_use ? 1 : 0; + if (glXSwapIntervalMESA) { + glXSwapIntervalMESA(val); + } else if (glXSwapIntervalSGI) { + glXSwapIntervalSGI(val); + } else if (glXSwapIntervalEXT) { + GLXDrawable drawable = glXGetCurrentDrawable(); + glXSwapIntervalEXT(disp.x11_display, drawable, val); + } else + return; + use_vsync = p_use; +} + +bool GLManager_X11::is_using_vsync() const { + return use_vsync; +} + +GLManager_X11::GLManager_X11(const Vector2i &p_size, ContextType p_context_type) { + context_type = p_context_type; + + double_buffer = false; + direct_render = false; + glx_minor = glx_major = 0; + use_vsync = false; + _current_window = nullptr; +} + +GLManager_X11::~GLManager_X11() { + release_current(); +} + +#endif +#endif diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h new file mode 100644 index 0000000000..fa2c8a9c84 --- /dev/null +++ b/platform/linuxbsd/gl_manager_x11.h @@ -0,0 +1,130 @@ +/*************************************************************************/ +/* gl_manager_x11.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GL_MANAGER_X11_H +#define GL_MANAGER_X11_H + +#ifdef X11_ENABLED + +#include "drivers/gles3/rasterizer_platforms.h" + +#ifdef GLES3_ENABLED + +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "servers/display_server.h" +#include <X11/Xlib.h> +#include <X11/extensions/Xrender.h> + +struct GLManager_X11_Private; + +class GLManager_X11 { +public: + enum ContextType { + GLES_3_0_COMPATIBLE, + }; + +private: + // any data specific to the window + struct GLWindow { + GLWindow() { in_use = false; } + bool in_use; + + // the external ID .. should match the GL window number .. unused I think + DisplayServer::WindowID window_id; + int width; + int height; + ::Window x11_window; + int gldisplay_id; + }; + + struct GLDisplay { + GLDisplay() { context = nullptr; } + ~GLDisplay(); + GLManager_X11_Private *context; + ::Display *x11_display; + XVisualInfo x_vi; + XSetWindowAttributes x_swa; + unsigned long x_valuemask; + }; + + // just for convenience, window and display struct + struct XWinDisp { + ::Window x11_window; + ::Display *x11_display; + } _x_windisp; + + LocalVector<GLWindow> _windows; + LocalVector<GLDisplay> _displays; + + GLWindow *_current_window; + + void _internal_set_current_window(GLWindow *p_win); + + GLWindow &get_window(unsigned int id) { return _windows[id]; } + const GLWindow &get_window(unsigned int id) const { return _windows[id]; } + + const GLDisplay &get_current_display() const { return _displays[_current_window->gldisplay_id]; } + const GLDisplay &get_display(unsigned int id) { return _displays[id]; } + + bool double_buffer; + bool direct_render; + int glx_minor, glx_major; + bool use_vsync; + ContextType context_type; + +private: + int _find_or_create_display(Display *p_x11_display); + Error _create_context(GLDisplay &gl_display); + +public: + 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); + + void release_current(); + void make_current(); + void swap_buffers(); + + void window_make_current(DisplayServer::WindowID p_window_id); + + Error initialize(); + + void set_use_vsync(bool p_use); + bool is_using_vsync() const; + + GLManager_X11(const Vector2i &p_size, ContextType p_context_type); + ~GLManager_X11(); +}; + +#endif // GLES3_ENABLED +#endif // X11_ENABLED + +#endif // GL_MANAGER_X11_H diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index e1796ccefe..6f5c46b59c 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index fda1358dfd..1c6afabfab 100644 --- a/platform/linuxbsd/joypad_linux.cpp +++ b/platform/linuxbsd/joypad_linux.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -32,13 +32,14 @@ #include "joypad_linux.h" +#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <linux/input.h> #include <unistd.h> #ifdef UDEV_ENABLED -#include <libudev.h> +#include "libudev-so_wrap.h" #endif #define LONG_BITS (sizeof(long) * 8) @@ -49,15 +50,6 @@ static const char *ignore_str = "/dev/input/js"; #endif -JoypadLinux::Joypad::Joypad() { - fd = -1; - dpad = 0; - devpath = ""; - for (int i = 0; i < MAX_ABS; i++) { - abs_info[i] = nullptr; - } -} - JoypadLinux::Joypad::~Joypad() { for (int i = 0; i < MAX_ABS; i++) { if (abs_info[i]) { @@ -67,10 +59,10 @@ JoypadLinux::Joypad::~Joypad() { } void JoypadLinux::Joypad::reset() { - dpad = 0; + dpad = HatMask::CENTER; fd = -1; - Input::JoyAxis jx; + Input::JoyAxisValue jx; jx.min = -1; jx.value = 0.0f; for (int i = 0; i < MAX_ABS; i++) { @@ -80,15 +72,28 @@ void JoypadLinux::Joypad::reset() { } JoypadLinux::JoypadLinux(Input *in) { - exit_udev = false; +#ifdef UDEV_ENABLED +#ifdef DEBUG_ENABLED + int dylibloader_verbose = 1; +#else + int dylibloader_verbose = 0; +#endif + use_udev = initialize_libudev(dylibloader_verbose) == 0; + if (use_udev) { + 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."); + } +#else + print_verbose("JoypadLinux: udev disabled, parsing /dev/input to detect joypads."); +#endif input = in; - joy_thread = Thread::create(joy_thread_func, this); + joy_thread.start(joy_thread_func, this); } JoypadLinux::~JoypadLinux() { - exit_udev = true; - Thread::wait_to_finish(joy_thread); - memdelete(joy_thread); + exit_monitor.set(); + joy_thread.wait_to_finish(); close_joypad(); } @@ -101,11 +106,20 @@ void JoypadLinux::joy_thread_func(void *p_user) { void JoypadLinux::run_joypad_thread() { #ifdef UDEV_ENABLED - udev *_udev = udev_new(); - ERR_FAIL_COND(!_udev); - enumerate_joypads(_udev); - monitor_joypads(_udev); - udev_unref(_udev); + if (use_udev) { + udev *_udev = udev_new(); + if (!_udev) { + use_udev = false; + ERR_PRINT("Failed getting an udev context, falling back to parsing /dev/input."); + monitor_joypads(); + } else { + enumerate_joypads(_udev); + monitor_joypads(_udev); + udev_unref(_udev); + } + } else { + monitor_joypads(); + } #else monitor_joypads(); #endif @@ -146,7 +160,7 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { udev_monitor_enable_receiving(mon); int fd = udev_monitor_get_fd(mon); - while (!exit_udev) { + while (!exit_monitor.is_set()) { fd_set fds; struct timeval tv; int ret; @@ -164,17 +178,18 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { select() ensured that this will not block. */ dev = udev_monitor_receive_device(mon); - if (dev && udev_device_get_devnode(dev) != 0) { + if (dev && udev_device_get_devnode(dev) != nullptr) { MutexLock lock(joy_mutex); String action = udev_device_get_action(dev); const char *devnode = udev_device_get_devnode(dev); if (devnode) { String devnode_str = devnode; if (devnode_str.find(ignore_str) == -1) { - if (action == "add") + if (action == "add") { open_joypad(devnode); - else if (String(action) == "remove") + } else if (String(action) == "remove") { close_joypad(get_joy_from_path(devnode)); + } } } @@ -188,17 +203,27 @@ void JoypadLinux::monitor_joypads(udev *p_udev) { #endif void JoypadLinux::monitor_joypads() { - while (!exit_udev) { + while (!exit_monitor.is_set()) { { MutexLock lock(joy_mutex); - for (int i = 0; i < 32; i++) { + DIR *input_directory; + input_directory = opendir("/dev/input"); + if (input_directory) { + struct dirent *current; char fname[64]; - sprintf(fname, "/dev/input/event%d", i); - if (attached_devices.find(fname) == -1) { - open_joypad(fname); + + while ((current = readdir(input_directory)) != nullptr) { + if (strncmp(current->d_name, "event", 5) != 0) { + continue; + } + sprintf(fname, "/dev/input/%.*s", 16, current->d_name); + if (attached_devices.find(fname) == -1) { + open_joypad(fname); + } } } + closedir(input_directory); } usleep(1000000); // 1s } @@ -404,10 +429,10 @@ void JoypadLinux::joypad_vibration_stop(int p_id, uint64_t p_timestamp) { joy.ff_effect_timestamp = p_timestamp; } -Input::JoyAxis JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { +Input::JoyAxisValue JoypadLinux::axis_correct(const input_absinfo *p_abs, int p_value) const { int min = p_abs->minimum; int max = p_abs->maximum; - Input::JoyAxis jx; + Input::JoyAxisValue jx; if (min < 0) { jx.min = -1; @@ -450,7 +475,7 @@ void JoypadLinux::process_joypads() { switch (ev.type) { case EV_KEY: - input->joy_button(i, joy->key_map[ev.code], ev.value); + input->joy_button(i, (JoyButton)joy->key_map[ev.code], ev.value); break; case EV_ABS: @@ -459,29 +484,29 @@ void JoypadLinux::process_joypads() { case ABS_HAT0X: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad |= Input::HAT_MASK_LEFT; + joy->dpad = (HatMask)((joy->dpad | HatMask::LEFT) & ~HatMask::RIGHT); } else { - joy->dpad |= Input::HAT_MASK_RIGHT; + joy->dpad = (HatMask)((joy->dpad | HatMask::RIGHT) & ~HatMask::LEFT); } } else { - joy->dpad &= ~(Input::HAT_MASK_LEFT | Input::HAT_MASK_RIGHT); + joy->dpad &= ~(HatMask::LEFT | HatMask::RIGHT); } - input->joy_hat(i, joy->dpad); + input->joy_hat(i, (HatMask)joy->dpad); break; case ABS_HAT0Y: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad |= Input::HAT_MASK_UP; + joy->dpad = (HatMask)((joy->dpad | HatMask::UP) & ~HatMask::DOWN); } else { - joy->dpad |= Input::HAT_MASK_DOWN; + joy->dpad = (HatMask)((joy->dpad | HatMask::DOWN) & ~HatMask::UP); } } else { - joy->dpad &= ~(Input::HAT_MASK_UP | Input::HAT_MASK_DOWN); + joy->dpad &= ~(HatMask::UP | HatMask::DOWN); } - input->joy_hat(i, joy->dpad); + input->joy_hat(i, (HatMask)joy->dpad); break; default: @@ -489,7 +514,7 @@ void JoypadLinux::process_joypads() { return; } if (joy->abs_map[ev.code] != -1 && joy->abs_info[ev.code]) { - Input::JoyAxis value = axis_correct(joy->abs_info[ev.code], ev.value); + Input::JoyAxisValue value = axis_correct(joy->abs_info[ev.code], ev.value); joy->curr_axis[joy->abs_map[ev.code]] = value; } break; @@ -501,7 +526,7 @@ void JoypadLinux::process_joypads() { for (int j = 0; j < MAX_ABS; j++) { int index = joy->abs_map[j]; if (index != -1) { - input->joy_axis(i, index, joy->curr_axis[index]); + input->joy_axis(i, (JoyAxis)index, joy->curr_axis[index]); } } if (len == 0 || (len < 0 && errno != EAGAIN)) { diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 0d175193a5..12b9046d64 100644 --- a/platform/linuxbsd/joypad_linux.h +++ b/platform/linuxbsd/joypad_linux.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -53,28 +53,30 @@ private: }; struct Joypad { - Input::JoyAxis curr_axis[MAX_ABS]; + Input::JoyAxisValue curr_axis[MAX_ABS]; int key_map[MAX_KEY]; int abs_map[MAX_ABS]; - int dpad; - int fd; + HatMask dpad = HatMask::CENTER; + int fd = -1; String devpath; - input_absinfo *abs_info[MAX_ABS]; + input_absinfo *abs_info[MAX_ABS] = {}; - bool force_feedback; - int ff_effect_id; - uint64_t ff_effect_timestamp; + bool force_feedback = false; + int ff_effect_id = 0; + uint64_t ff_effect_timestamp = 0; - Joypad(); ~Joypad(); void reset(); }; - bool exit_udev; +#ifdef UDEV_ENABLED + bool use_udev = false; +#endif + SafeFlag exit_monitor; Mutex joy_mutex; - Thread *joy_thread; - Input *input; + Thread joy_thread; + Input *input = nullptr; Joypad joypads[JOYPADS_MAX]; Vector<String> attached_devices; @@ -95,7 +97,7 @@ private: void joypad_vibration_start(int p_id, float p_weak_magnitude, float p_strong_magnitude, float p_duration, uint64_t p_timestamp); void joypad_vibration_stop(int p_id, uint64_t p_timestamp); - Input::JoyAxis axis_correct(const input_absinfo *p_abs, int p_value) const; + Input::JoyAxisValue axis_correct(const input_absinfo *p_abs, int p_value) const; }; #endif diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp index 77512b1a9e..16c2392859 100644 --- a/platform/linuxbsd/key_mapping_x11.cpp +++ b/platform/linuxbsd/key_mapping_x11.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -34,273 +34,272 @@ struct _XTranslatePair { KeySym keysym; - unsigned int keycode; + Key keycode; }; static _XTranslatePair _xkeysym_to_keycode[] = { // misc keys - { XK_Escape, KEY_ESCAPE }, - { XK_Tab, KEY_TAB }, - { XK_ISO_Left_Tab, KEY_BACKTAB }, - { XK_BackSpace, KEY_BACKSPACE }, - { XK_Return, KEY_ENTER }, - { XK_Insert, KEY_INSERT }, - { XK_Delete, KEY_DELETE }, - { XK_Clear, KEY_DELETE }, - { XK_Pause, KEY_PAUSE }, - { XK_Print, KEY_PRINT }, - { XK_Home, KEY_HOME }, - { XK_End, KEY_END }, - { XK_Left, KEY_LEFT }, - { XK_Up, KEY_UP }, - { XK_Right, KEY_RIGHT }, - { XK_Down, KEY_DOWN }, - { XK_Prior, KEY_PAGEUP }, - { XK_Next, KEY_PAGEDOWN }, - { XK_Shift_L, KEY_SHIFT }, - { XK_Shift_R, KEY_SHIFT }, - { XK_Shift_Lock, KEY_SHIFT }, - { XK_Control_L, KEY_CONTROL }, - { XK_Control_R, KEY_CONTROL }, - { XK_Meta_L, KEY_META }, - { XK_Meta_R, KEY_META }, - { XK_Alt_L, KEY_ALT }, - { XK_Alt_R, KEY_ALT }, - { XK_Caps_Lock, KEY_CAPSLOCK }, - { XK_Num_Lock, KEY_NUMLOCK }, - { XK_Scroll_Lock, KEY_SCROLLLOCK }, - { XK_Super_L, KEY_SUPER_L }, - { XK_Super_R, KEY_SUPER_R }, - { XK_Menu, KEY_MENU }, - { XK_Hyper_L, KEY_HYPER_L }, - { XK_Hyper_R, KEY_HYPER_R }, - { XK_Help, KEY_HELP }, - { XK_KP_Space, KEY_SPACE }, - { XK_KP_Tab, KEY_TAB }, - { XK_KP_Enter, KEY_KP_ENTER }, - { XK_Home, KEY_HOME }, - { XK_Left, KEY_LEFT }, - { XK_Up, KEY_UP }, - { XK_Right, KEY_RIGHT }, - { XK_Down, KEY_DOWN }, - { XK_Prior, KEY_PAGEUP }, - { XK_Next, KEY_PAGEDOWN }, - { XK_End, KEY_END }, - { XK_Begin, KEY_CLEAR }, - { XK_Insert, KEY_INSERT }, - { XK_Delete, KEY_DELETE }, - //{ XK_KP_Equal, KEY_EQUAL }, - //{ XK_KP_Separator, KEY_COMMA }, - { XK_KP_Decimal, KEY_KP_PERIOD }, - { XK_KP_Delete, KEY_KP_PERIOD }, - { XK_KP_Multiply, KEY_KP_MULTIPLY }, - { XK_KP_Divide, KEY_KP_DIVIDE }, - { XK_KP_Subtract, KEY_KP_SUBTRACT }, - { XK_KP_Add, KEY_KP_ADD }, - { XK_KP_0, KEY_KP_0 }, - { XK_KP_1, KEY_KP_1 }, - { XK_KP_2, KEY_KP_2 }, - { XK_KP_3, KEY_KP_3 }, - { XK_KP_4, KEY_KP_4 }, - { XK_KP_5, KEY_KP_5 }, - { XK_KP_6, KEY_KP_6 }, - { XK_KP_7, KEY_KP_7 }, - { XK_KP_8, KEY_KP_8 }, - { XK_KP_9, KEY_KP_9 }, + { XK_Escape, Key::ESCAPE }, + { XK_Tab, Key::TAB }, + { XK_ISO_Left_Tab, Key::BACKTAB }, + { XK_BackSpace, Key::BACKSPACE }, + { XK_Return, Key::ENTER }, + { XK_Insert, Key::INSERT }, + { XK_Delete, Key::KEY_DELETE }, + { XK_Clear, Key::KEY_DELETE }, + { XK_Pause, Key::PAUSE }, + { XK_Print, Key::PRINT }, + { XK_Home, Key::HOME }, + { XK_End, Key::END }, + { XK_Left, Key::LEFT }, + { XK_Up, Key::UP }, + { XK_Right, Key::RIGHT }, + { XK_Down, Key::DOWN }, + { XK_Prior, Key::PAGEUP }, + { XK_Next, Key::PAGEDOWN }, + { XK_Shift_L, Key::SHIFT }, + { XK_Shift_R, Key::SHIFT }, + { XK_Shift_Lock, Key::SHIFT }, + { XK_Control_L, Key::CTRL }, + { XK_Control_R, Key::CTRL }, + { XK_Meta_L, Key::META }, + { XK_Meta_R, Key::META }, + { XK_Alt_L, Key::ALT }, + { XK_Alt_R, Key::ALT }, + { XK_Caps_Lock, Key::CAPSLOCK }, + { XK_Num_Lock, Key::NUMLOCK }, + { XK_Scroll_Lock, Key::SCROLLLOCK }, + { XK_Super_L, Key::SUPER_L }, + { XK_Super_R, Key::SUPER_R }, + { XK_Menu, Key::MENU }, + { XK_Hyper_L, Key::HYPER_L }, + { XK_Hyper_R, Key::HYPER_R }, + { XK_Help, Key::HELP }, + { XK_KP_Space, Key::SPACE }, + { XK_KP_Tab, Key::TAB }, + { XK_KP_Enter, Key::KP_ENTER }, + { XK_Home, Key::HOME }, + { XK_Left, Key::LEFT }, + { XK_Up, Key::UP }, + { XK_Right, Key::RIGHT }, + { XK_Down, Key::DOWN }, + { XK_Prior, Key::PAGEUP }, + { XK_Next, Key::PAGEDOWN }, + { XK_End, Key::END }, + { XK_Begin, Key::CLEAR }, + { XK_Insert, Key::INSERT }, + { XK_Delete, Key::KEY_DELETE }, + //{ XK_KP_Equal, Key::EQUAL }, + //{ XK_KP_Separator, Key::COMMA }, + { XK_KP_Decimal, Key::KP_PERIOD }, + { XK_KP_Delete, Key::KP_PERIOD }, + { XK_KP_Multiply, Key::KP_MULTIPLY }, + { XK_KP_Divide, Key::KP_DIVIDE }, + { XK_KP_Subtract, Key::KP_SUBTRACT }, + { XK_KP_Add, Key::KP_ADD }, + { XK_KP_0, Key::KP_0 }, + { XK_KP_1, Key::KP_1 }, + { XK_KP_2, Key::KP_2 }, + { XK_KP_3, Key::KP_3 }, + { XK_KP_4, Key::KP_4 }, + { XK_KP_5, Key::KP_5 }, + { XK_KP_6, Key::KP_6 }, + { XK_KP_7, Key::KP_7 }, + { XK_KP_8, Key::KP_8 }, + { XK_KP_9, Key::KP_9 }, // same but with numlock - { XK_KP_Insert, KEY_KP_0 }, - { XK_KP_End, KEY_KP_1 }, - { XK_KP_Down, KEY_KP_2 }, - { XK_KP_Page_Down, KEY_KP_3 }, - { XK_KP_Left, KEY_KP_4 }, - { XK_KP_Begin, KEY_KP_5 }, - { XK_KP_Right, KEY_KP_6 }, - { XK_KP_Home, KEY_KP_7 }, - { XK_KP_Up, KEY_KP_8 }, - { XK_KP_Page_Up, KEY_KP_9 }, - { XK_F1, KEY_F1 }, - { XK_F2, KEY_F2 }, - { XK_F3, KEY_F3 }, - { XK_F4, KEY_F4 }, - { XK_F5, KEY_F5 }, - { XK_F6, KEY_F6 }, - { XK_F7, KEY_F7 }, - { XK_F8, KEY_F8 }, - { XK_F9, KEY_F9 }, - { XK_F10, KEY_F10 }, - { XK_F11, KEY_F11 }, - { XK_F12, KEY_F12 }, - { XK_F13, KEY_F13 }, - { XK_F14, KEY_F14 }, - { XK_F15, KEY_F15 }, - { XK_F16, KEY_F16 }, + { XK_KP_Insert, Key::KP_0 }, + { XK_KP_End, Key::KP_1 }, + { XK_KP_Down, Key::KP_2 }, + { XK_KP_Page_Down, Key::KP_3 }, + { XK_KP_Left, Key::KP_4 }, + { XK_KP_Begin, Key::KP_5 }, + { XK_KP_Right, Key::KP_6 }, + { XK_KP_Home, Key::KP_7 }, + { XK_KP_Up, Key::KP_8 }, + { XK_KP_Page_Up, Key::KP_9 }, + { XK_F1, Key::F1 }, + { XK_F2, Key::F2 }, + { XK_F3, Key::F3 }, + { XK_F4, Key::F4 }, + { XK_F5, Key::F5 }, + { XK_F6, Key::F6 }, + { XK_F7, Key::F7 }, + { XK_F8, Key::F8 }, + { XK_F9, Key::F9 }, + { XK_F10, Key::F10 }, + { XK_F11, Key::F11 }, + { XK_F12, Key::F12 }, + { XK_F13, Key::F13 }, + { XK_F14, Key::F14 }, + { XK_F15, Key::F15 }, + { XK_F16, Key::F16 }, // media keys - { XF86XK_Back, KEY_BACK }, - { XF86XK_Forward, KEY_FORWARD }, - { XF86XK_Stop, KEY_STOP }, - { XF86XK_Refresh, KEY_REFRESH }, - { XF86XK_Favorites, KEY_FAVORITES }, - { XF86XK_AudioMedia, KEY_LAUNCHMEDIA }, - { XF86XK_OpenURL, KEY_OPENURL }, - { XF86XK_HomePage, KEY_HOMEPAGE }, - { XF86XK_Search, KEY_SEARCH }, - { XF86XK_AudioLowerVolume, KEY_VOLUMEDOWN }, - { XF86XK_AudioMute, KEY_VOLUMEMUTE }, - { XF86XK_AudioRaiseVolume, KEY_VOLUMEUP }, - { XF86XK_AudioPlay, KEY_MEDIAPLAY }, - { XF86XK_AudioStop, KEY_MEDIASTOP }, - { XF86XK_AudioPrev, KEY_MEDIAPREVIOUS }, - { XF86XK_AudioNext, KEY_MEDIANEXT }, - { XF86XK_AudioRecord, KEY_MEDIARECORD }, + { XF86XK_Back, Key::BACK }, + { XF86XK_Forward, Key::FORWARD }, + { XF86XK_Stop, Key::STOP }, + { XF86XK_Refresh, Key::REFRESH }, + { XF86XK_Favorites, Key::FAVORITES }, + { XF86XK_AudioMedia, Key::LAUNCHMEDIA }, + { XF86XK_OpenURL, Key::OPENURL }, + { XF86XK_HomePage, Key::HOMEPAGE }, + { XF86XK_Search, Key::SEARCH }, + { XF86XK_AudioLowerVolume, Key::VOLUMEDOWN }, + { XF86XK_AudioMute, Key::VOLUMEMUTE }, + { XF86XK_AudioRaiseVolume, Key::VOLUMEUP }, + { XF86XK_AudioPlay, Key::MEDIAPLAY }, + { XF86XK_AudioStop, Key::MEDIASTOP }, + { XF86XK_AudioPrev, Key::MEDIAPREVIOUS }, + { XF86XK_AudioNext, Key::MEDIANEXT }, + { XF86XK_AudioRecord, Key::MEDIARECORD }, // launch keys - { XF86XK_Mail, KEY_LAUNCHMAIL }, - { XF86XK_MyComputer, KEY_LAUNCH0 }, - { XF86XK_Calculator, KEY_LAUNCH1 }, - { XF86XK_Standby, KEY_STANDBY }, + { XF86XK_Mail, Key::LAUNCHMAIL }, + { XF86XK_MyComputer, Key::LAUNCH0 }, + { XF86XK_Calculator, Key::LAUNCH1 }, + { XF86XK_Standby, Key::STANDBY }, - { XF86XK_Launch0, KEY_LAUNCH2 }, - { XF86XK_Launch1, KEY_LAUNCH3 }, - { XF86XK_Launch2, KEY_LAUNCH4 }, - { XF86XK_Launch3, KEY_LAUNCH5 }, - { XF86XK_Launch4, KEY_LAUNCH6 }, - { XF86XK_Launch5, KEY_LAUNCH7 }, - { XF86XK_Launch6, KEY_LAUNCH8 }, - { XF86XK_Launch7, KEY_LAUNCH9 }, - { XF86XK_Launch8, KEY_LAUNCHA }, - { XF86XK_Launch9, KEY_LAUNCHB }, - { XF86XK_LaunchA, KEY_LAUNCHC }, - { XF86XK_LaunchB, KEY_LAUNCHD }, - { XF86XK_LaunchC, KEY_LAUNCHE }, - { XF86XK_LaunchD, KEY_LAUNCHF }, + { XF86XK_Launch0, Key::LAUNCH2 }, + { XF86XK_Launch1, Key::LAUNCH3 }, + { XF86XK_Launch2, Key::LAUNCH4 }, + { XF86XK_Launch3, Key::LAUNCH5 }, + { XF86XK_Launch4, Key::LAUNCH6 }, + { XF86XK_Launch5, Key::LAUNCH7 }, + { XF86XK_Launch6, Key::LAUNCH8 }, + { XF86XK_Launch7, Key::LAUNCH9 }, + { XF86XK_Launch8, Key::LAUNCHA }, + { XF86XK_Launch9, Key::LAUNCHB }, + { XF86XK_LaunchA, Key::LAUNCHC }, + { XF86XK_LaunchB, Key::LAUNCHD }, + { XF86XK_LaunchC, Key::LAUNCHE }, + { XF86XK_LaunchD, Key::LAUNCHF }, - { 0, 0 } + { 0, Key::NONE } }; struct _TranslatePair { - unsigned int keysym; + Key keysym; unsigned int keycode; }; static _TranslatePair _scancode_to_keycode[] = { - - { KEY_ESCAPE, 0x09 }, - { KEY_1, 0x0A }, - { KEY_2, 0x0B }, - { KEY_3, 0x0C }, - { KEY_4, 0x0D }, - { KEY_5, 0x0E }, - { KEY_6, 0x0F }, - { KEY_7, 0x10 }, - { KEY_8, 0x11 }, - { KEY_9, 0x12 }, - { KEY_0, 0x13 }, - { KEY_MINUS, 0x14 }, - { KEY_EQUAL, 0x15 }, - { KEY_BACKSPACE, 0x16 }, - { KEY_TAB, 0x17 }, - { KEY_Q, 0x18 }, - { KEY_W, 0x19 }, - { KEY_E, 0x1A }, - { KEY_R, 0x1B }, - { KEY_T, 0x1C }, - { KEY_Y, 0x1D }, - { KEY_U, 0x1E }, - { KEY_I, 0x1F }, - { KEY_O, 0x20 }, - { KEY_P, 0x21 }, - { KEY_BRACELEFT, 0x22 }, - { KEY_BRACERIGHT, 0x23 }, - { KEY_ENTER, 0x24 }, - { KEY_CONTROL, 0x25 }, - { KEY_A, 0x26 }, - { KEY_S, 0x27 }, - { KEY_D, 0x28 }, - { KEY_F, 0x29 }, - { KEY_G, 0x2A }, - { KEY_H, 0x2B }, - { KEY_J, 0x2C }, - { KEY_K, 0x2D }, - { KEY_L, 0x2E }, - { KEY_SEMICOLON, 0x2F }, - { KEY_APOSTROPHE, 0x30 }, - { KEY_QUOTELEFT, 0x31 }, - { KEY_SHIFT, 0x32 }, - { KEY_BACKSLASH, 0x33 }, - { KEY_Z, 0x34 }, - { KEY_X, 0x35 }, - { KEY_C, 0x36 }, - { KEY_V, 0x37 }, - { KEY_B, 0x38 }, - { KEY_N, 0x39 }, - { KEY_M, 0x3A }, - { KEY_COMMA, 0x3B }, - { KEY_PERIOD, 0x3C }, - { KEY_SLASH, 0x3D }, - { KEY_SHIFT, 0x3E }, - { KEY_KP_MULTIPLY, 0x3F }, - { KEY_ALT, 0x40 }, - { KEY_SPACE, 0x41 }, - { KEY_CAPSLOCK, 0x42 }, - { KEY_F1, 0x43 }, - { KEY_F2, 0x44 }, - { KEY_F3, 0x45 }, - { KEY_F4, 0x46 }, - { KEY_F5, 0x47 }, - { KEY_F6, 0x48 }, - { KEY_F7, 0x49 }, - { KEY_F8, 0x4A }, - { KEY_F9, 0x4B }, - { KEY_F10, 0x4C }, - { KEY_NUMLOCK, 0x4D }, - { KEY_SCROLLLOCK, 0x4E }, - { KEY_KP_7, 0x4F }, - { KEY_KP_8, 0x50 }, - { KEY_KP_9, 0x51 }, - { KEY_KP_SUBTRACT, 0x52 }, - { KEY_KP_4, 0x53 }, - { KEY_KP_5, 0x54 }, - { KEY_KP_6, 0x55 }, - { KEY_KP_ADD, 0x56 }, - { KEY_KP_1, 0x57 }, - { KEY_KP_2, 0x58 }, - { KEY_KP_3, 0x59 }, - { KEY_KP_0, 0x5A }, - { KEY_KP_PERIOD, 0x5B }, - //{ KEY_???, 0x5E }, //NON US BACKSLASH - { KEY_F11, 0x5F }, - { KEY_F12, 0x60 }, - { KEY_KP_ENTER, 0x68 }, - { KEY_CONTROL, 0x69 }, - { KEY_KP_DIVIDE, 0x6A }, - { KEY_PRINT, 0x6B }, - { KEY_ALT, 0x6C }, - { KEY_ENTER, 0x6D }, - { KEY_HOME, 0x6E }, - { KEY_UP, 0x6F }, - { KEY_PAGEUP, 0x70 }, - { KEY_LEFT, 0x71 }, - { KEY_RIGHT, 0x72 }, - { KEY_END, 0x73 }, - { KEY_DOWN, 0x74 }, - { KEY_PAGEDOWN, 0x75 }, - { KEY_INSERT, 0x76 }, - { KEY_DELETE, 0x77 }, - { KEY_VOLUMEMUTE, 0x79 }, - { KEY_VOLUMEDOWN, 0x7A }, - { KEY_VOLUMEUP, 0x7B }, - { KEY_PAUSE, 0x7F }, - { KEY_SUPER_L, 0x85 }, - { KEY_SUPER_R, 0x86 }, - { KEY_MENU, 0x87 }, - { KEY_UNKNOWN, 0 } + { Key::ESCAPE, 0x09 }, + { Key::KEY_1, 0x0A }, + { Key::KEY_2, 0x0B }, + { Key::KEY_3, 0x0C }, + { Key::KEY_4, 0x0D }, + { Key::KEY_5, 0x0E }, + { Key::KEY_6, 0x0F }, + { Key::KEY_7, 0x10 }, + { Key::KEY_8, 0x11 }, + { Key::KEY_9, 0x12 }, + { Key::KEY_0, 0x13 }, + { Key::MINUS, 0x14 }, + { Key::EQUAL, 0x15 }, + { Key::BACKSPACE, 0x16 }, + { Key::TAB, 0x17 }, + { Key::Q, 0x18 }, + { Key::W, 0x19 }, + { Key::E, 0x1A }, + { Key::R, 0x1B }, + { Key::T, 0x1C }, + { Key::Y, 0x1D }, + { Key::U, 0x1E }, + { Key::I, 0x1F }, + { Key::O, 0x20 }, + { Key::P, 0x21 }, + { Key::BRACELEFT, 0x22 }, + { Key::BRACERIGHT, 0x23 }, + { Key::ENTER, 0x24 }, + { Key::CTRL, 0x25 }, + { Key::A, 0x26 }, + { Key::S, 0x27 }, + { Key::D, 0x28 }, + { Key::F, 0x29 }, + { Key::G, 0x2A }, + { Key::H, 0x2B }, + { Key::J, 0x2C }, + { Key::K, 0x2D }, + { Key::L, 0x2E }, + { Key::SEMICOLON, 0x2F }, + { Key::APOSTROPHE, 0x30 }, + { Key::QUOTELEFT, 0x31 }, + { Key::SHIFT, 0x32 }, + { Key::BACKSLASH, 0x33 }, + { Key::Z, 0x34 }, + { Key::X, 0x35 }, + { Key::C, 0x36 }, + { Key::V, 0x37 }, + { Key::B, 0x38 }, + { Key::N, 0x39 }, + { Key::M, 0x3A }, + { Key::COMMA, 0x3B }, + { Key::PERIOD, 0x3C }, + { Key::SLASH, 0x3D }, + { Key::SHIFT, 0x3E }, + { Key::KP_MULTIPLY, 0x3F }, + { Key::ALT, 0x40 }, + { Key::SPACE, 0x41 }, + { Key::CAPSLOCK, 0x42 }, + { Key::F1, 0x43 }, + { Key::F2, 0x44 }, + { Key::F3, 0x45 }, + { Key::F4, 0x46 }, + { Key::F5, 0x47 }, + { Key::F6, 0x48 }, + { Key::F7, 0x49 }, + { Key::F8, 0x4A }, + { Key::F9, 0x4B }, + { Key::F10, 0x4C }, + { Key::NUMLOCK, 0x4D }, + { Key::SCROLLLOCK, 0x4E }, + { Key::KP_7, 0x4F }, + { Key::KP_8, 0x50 }, + { Key::KP_9, 0x51 }, + { Key::KP_SUBTRACT, 0x52 }, + { Key::KP_4, 0x53 }, + { Key::KP_5, 0x54 }, + { Key::KP_6, 0x55 }, + { Key::KP_ADD, 0x56 }, + { Key::KP_1, 0x57 }, + { Key::KP_2, 0x58 }, + { Key::KP_3, 0x59 }, + { Key::KP_0, 0x5A }, + { Key::KP_PERIOD, 0x5B }, + //{ Key::???, 0x5E }, //NON US BACKSLASH + { Key::F11, 0x5F }, + { Key::F12, 0x60 }, + { Key::KP_ENTER, 0x68 }, + { Key::CTRL, 0x69 }, + { Key::KP_DIVIDE, 0x6A }, + { Key::PRINT, 0x6B }, + { Key::ALT, 0x6C }, + { Key::ENTER, 0x6D }, + { Key::HOME, 0x6E }, + { Key::UP, 0x6F }, + { Key::PAGEUP, 0x70 }, + { Key::LEFT, 0x71 }, + { Key::RIGHT, 0x72 }, + { Key::END, 0x73 }, + { Key::DOWN, 0x74 }, + { Key::PAGEDOWN, 0x75 }, + { Key::INSERT, 0x76 }, + { Key::KEY_DELETE, 0x77 }, + { Key::VOLUMEMUTE, 0x79 }, + { Key::VOLUMEDOWN, 0x7A }, + { Key::VOLUMEUP, 0x7B }, + { Key::PAUSE, 0x7F }, + { Key::SUPER_L, 0x85 }, + { Key::SUPER_R, 0x86 }, + { Key::MENU, 0x87 }, + { Key::UNKNOWN, 0 } }; -unsigned int KeyMappingX11::get_scancode(unsigned int p_code) { - unsigned int keycode = KEY_UNKNOWN; - for (int i = 0; _scancode_to_keycode[i].keysym != KEY_UNKNOWN; i++) { +Key KeyMappingX11::get_scancode(unsigned int p_code) { + Key keycode = Key::UNKNOWN; + for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) { if (_scancode_to_keycode[i].keycode == p_code) { keycode = _scancode_to_keycode[i].keysym; break; @@ -310,11 +309,23 @@ unsigned int KeyMappingX11::get_scancode(unsigned int p_code) { return keycode; } -unsigned int KeyMappingX11::get_keycode(KeySym p_keysym) { +unsigned int KeyMappingX11::get_xlibcode(Key p_keysym) { + unsigned int code = 0; + for (int i = 0; _scancode_to_keycode[i].keysym != Key::UNKNOWN; i++) { + if (_scancode_to_keycode[i].keysym == p_keysym) { + code = _scancode_to_keycode[i].keycode; + break; + } + } + + return code; +} + +Key KeyMappingX11::get_keycode(KeySym p_keysym) { // kinda bruteforce.. could optimize. if (p_keysym < 0x100) { // Latin 1, maps 1-1 - return p_keysym; + return (Key)p_keysym; } // look for special key @@ -324,14 +335,14 @@ unsigned int KeyMappingX11::get_keycode(KeySym p_keysym) { } } - return 0; + return Key::NONE; } -KeySym KeyMappingX11::get_keysym(unsigned int p_code) { +KeySym KeyMappingX11::get_keysym(Key p_code) { // kinda bruteforce.. could optimize. - if (p_code < 0x100) { // Latin 1, maps 1-1 - return p_code; + if (p_code < Key::END_LATIN1) { // Latin 1, maps 1-1 + return (KeySym)p_code; } // look for special key @@ -341,7 +352,7 @@ KeySym KeyMappingX11::get_keysym(unsigned int p_code) { } } - return 0; + return (KeySym)Key::NONE; } /***** UNICODE CONVERSION ******/ @@ -354,7 +365,6 @@ struct _XTranslateUnicodePair { }; enum { - _KEYSYM_MAX = 759 }; @@ -1160,7 +1170,6 @@ struct _XTranslateUnicodePairReverse { }; enum { - _UNICODE_MAX = 750 }; diff --git a/platform/linuxbsd/key_mapping_x11.h b/platform/linuxbsd/key_mapping_x11.h index 8f5e01a3c2..5f61197abe 100644 --- a/platform/linuxbsd/key_mapping_x11.h +++ b/platform/linuxbsd/key_mapping_x11.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -44,11 +44,12 @@ class KeyMappingX11 { KeyMappingX11() {} public: - static unsigned int get_keycode(KeySym p_keysym); - static unsigned int get_scancode(unsigned int p_code); - static KeySym get_keysym(unsigned int p_code); + static Key get_keycode(KeySym p_keysym); + static unsigned int get_xlibcode(Key p_keysym); + static Key get_scancode(unsigned int p_code); + static KeySym get_keysym(Key p_code); static unsigned int get_unicode_from_keysym(KeySym p_keysym); static KeySym get_keysym_from_unicode(unsigned int p_unicode); }; -#endif +#endif // KEY_MAPPING_X11_H diff --git a/platform/linuxbsd/libudev-so_wrap.c b/platform/linuxbsd/libudev-so_wrap.c new file mode 100644 index 0000000000..a9fa4a494a --- /dev/null +++ b/platform/linuxbsd/libudev-so_wrap.c @@ -0,0 +1,1013 @@ +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:59 +// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/libudev.h --sys-include <libudev.h> --soname libudev.so.1 --init-name libudev --omit-prefix gnu_ --output-header libudev-so_wrap.h --output-implementation libudev-so_wrap.c +// +#include <stdint.h> + +#define udev_ref udev_ref_dylibloader_orig_libudev +#define udev_unref udev_unref_dylibloader_orig_libudev +#define udev_new udev_new_dylibloader_orig_libudev +#define udev_set_log_fn udev_set_log_fn_dylibloader_orig_libudev +#define udev_get_log_priority udev_get_log_priority_dylibloader_orig_libudev +#define udev_set_log_priority udev_set_log_priority_dylibloader_orig_libudev +#define udev_get_userdata udev_get_userdata_dylibloader_orig_libudev +#define udev_set_userdata udev_set_userdata_dylibloader_orig_libudev +#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_orig_libudev +#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_orig_libudev +#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_orig_libudev +#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_orig_libudev +#define udev_device_ref udev_device_ref_dylibloader_orig_libudev +#define udev_device_unref udev_device_unref_dylibloader_orig_libudev +#define udev_device_get_udev udev_device_get_udev_dylibloader_orig_libudev +#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_orig_libudev +#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_orig_libudev +#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_orig_libudev +#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_orig_libudev +#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_orig_libudev +#define udev_device_get_parent udev_device_get_parent_dylibloader_orig_libudev +#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_orig_libudev +#define udev_device_get_devpath udev_device_get_devpath_dylibloader_orig_libudev +#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_orig_libudev +#define udev_device_get_devtype udev_device_get_devtype_dylibloader_orig_libudev +#define udev_device_get_syspath udev_device_get_syspath_dylibloader_orig_libudev +#define udev_device_get_sysname udev_device_get_sysname_dylibloader_orig_libudev +#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_orig_libudev +#define udev_device_get_devnode udev_device_get_devnode_dylibloader_orig_libudev +#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_orig_libudev +#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_orig_libudev +#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_orig_libudev +#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_orig_libudev +#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_orig_libudev +#define udev_device_get_property_value udev_device_get_property_value_dylibloader_orig_libudev +#define udev_device_get_driver udev_device_get_driver_dylibloader_orig_libudev +#define udev_device_get_devnum udev_device_get_devnum_dylibloader_orig_libudev +#define udev_device_get_action udev_device_get_action_dylibloader_orig_libudev +#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_orig_libudev +#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_orig_libudev +#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_orig_libudev +#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_orig_libudev +#define udev_device_has_tag udev_device_has_tag_dylibloader_orig_libudev +#define udev_monitor_ref udev_monitor_ref_dylibloader_orig_libudev +#define udev_monitor_unref udev_monitor_unref_dylibloader_orig_libudev +#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_orig_libudev +#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_orig_libudev +#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_orig_libudev +#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_orig_libudev +#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_orig_libudev +#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_orig_libudev +#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_orig_libudev +#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_orig_libudev +#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_orig_libudev +#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_orig_libudev +#define udev_enumerate_ref udev_enumerate_ref_dylibloader_orig_libudev +#define udev_enumerate_unref udev_enumerate_unref_dylibloader_orig_libudev +#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_orig_libudev +#define udev_enumerate_new udev_enumerate_new_dylibloader_orig_libudev +#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_orig_libudev +#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_orig_libudev +#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_orig_libudev +#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_orig_libudev +#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_orig_libudev +#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_orig_libudev +#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_orig_libudev +#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_orig_libudev +#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_orig_libudev +#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_orig_libudev +#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_orig_libudev +#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_orig_libudev +#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_orig_libudev +#define udev_queue_ref udev_queue_ref_dylibloader_orig_libudev +#define udev_queue_unref udev_queue_unref_dylibloader_orig_libudev +#define udev_queue_get_udev udev_queue_get_udev_dylibloader_orig_libudev +#define udev_queue_new udev_queue_new_dylibloader_orig_libudev +#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_orig_libudev +#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_orig_libudev +#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_orig_libudev +#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_orig_libudev +#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_orig_libudev +#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_orig_libudev +#define udev_queue_get_fd udev_queue_get_fd_dylibloader_orig_libudev +#define udev_queue_flush udev_queue_flush_dylibloader_orig_libudev +#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_orig_libudev +#define udev_hwdb_new udev_hwdb_new_dylibloader_orig_libudev +#define udev_hwdb_ref udev_hwdb_ref_dylibloader_orig_libudev +#define udev_hwdb_unref udev_hwdb_unref_dylibloader_orig_libudev +#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_orig_libudev +#define udev_util_encode_string udev_util_encode_string_dylibloader_orig_libudev +#include <libudev.h> +#undef udev_ref +#undef udev_unref +#undef udev_new +#undef udev_set_log_fn +#undef udev_get_log_priority +#undef udev_set_log_priority +#undef udev_get_userdata +#undef udev_set_userdata +#undef udev_list_entry_get_next +#undef udev_list_entry_get_by_name +#undef udev_list_entry_get_name +#undef udev_list_entry_get_value +#undef udev_device_ref +#undef udev_device_unref +#undef udev_device_get_udev +#undef udev_device_new_from_syspath +#undef udev_device_new_from_devnum +#undef udev_device_new_from_subsystem_sysname +#undef udev_device_new_from_device_id +#undef udev_device_new_from_environment +#undef udev_device_get_parent +#undef udev_device_get_parent_with_subsystem_devtype +#undef udev_device_get_devpath +#undef udev_device_get_subsystem +#undef udev_device_get_devtype +#undef udev_device_get_syspath +#undef udev_device_get_sysname +#undef udev_device_get_sysnum +#undef udev_device_get_devnode +#undef udev_device_get_is_initialized +#undef udev_device_get_devlinks_list_entry +#undef udev_device_get_properties_list_entry +#undef udev_device_get_tags_list_entry +#undef udev_device_get_sysattr_list_entry +#undef udev_device_get_property_value +#undef udev_device_get_driver +#undef udev_device_get_devnum +#undef udev_device_get_action +#undef udev_device_get_seqnum +#undef udev_device_get_usec_since_initialized +#undef udev_device_get_sysattr_value +#undef udev_device_set_sysattr_value +#undef udev_device_has_tag +#undef udev_monitor_ref +#undef udev_monitor_unref +#undef udev_monitor_get_udev +#undef udev_monitor_new_from_netlink +#undef udev_monitor_enable_receiving +#undef udev_monitor_set_receive_buffer_size +#undef udev_monitor_get_fd +#undef udev_monitor_receive_device +#undef udev_monitor_filter_add_match_subsystem_devtype +#undef udev_monitor_filter_add_match_tag +#undef udev_monitor_filter_update +#undef udev_monitor_filter_remove +#undef udev_enumerate_ref +#undef udev_enumerate_unref +#undef udev_enumerate_get_udev +#undef udev_enumerate_new +#undef udev_enumerate_add_match_subsystem +#undef udev_enumerate_add_nomatch_subsystem +#undef udev_enumerate_add_match_sysattr +#undef udev_enumerate_add_nomatch_sysattr +#undef udev_enumerate_add_match_property +#undef udev_enumerate_add_match_sysname +#undef udev_enumerate_add_match_tag +#undef udev_enumerate_add_match_parent +#undef udev_enumerate_add_match_is_initialized +#undef udev_enumerate_add_syspath +#undef udev_enumerate_scan_devices +#undef udev_enumerate_scan_subsystems +#undef udev_enumerate_get_list_entry +#undef udev_queue_ref +#undef udev_queue_unref +#undef udev_queue_get_udev +#undef udev_queue_new +#undef udev_queue_get_kernel_seqnum +#undef udev_queue_get_udev_seqnum +#undef udev_queue_get_udev_is_active +#undef udev_queue_get_queue_is_empty +#undef udev_queue_get_seqnum_is_finished +#undef udev_queue_get_seqnum_sequence_is_finished +#undef udev_queue_get_fd +#undef udev_queue_flush +#undef udev_queue_get_queued_list_entry +#undef udev_hwdb_new +#undef udev_hwdb_ref +#undef udev_hwdb_unref +#undef udev_hwdb_get_properties_list_entry +#undef udev_util_encode_string +#include <dlfcn.h> +#include <stdio.h> +struct udev* (*udev_ref_dylibloader_wrapper_libudev)(struct udev*); +struct udev* (*udev_unref_dylibloader_wrapper_libudev)(struct udev*); +struct udev* (*udev_new_dylibloader_wrapper_libudev)( void); +void (*udev_set_log_fn_dylibloader_wrapper_libudev)(struct udev*, void*); +int (*udev_get_log_priority_dylibloader_wrapper_libudev)(struct udev*); +void (*udev_set_log_priority_dylibloader_wrapper_libudev)(struct udev*, int); +void* (*udev_get_userdata_dylibloader_wrapper_libudev)(struct udev*); +void (*udev_set_userdata_dylibloader_wrapper_libudev)(struct udev*, void*); +struct udev_list_entry* (*udev_list_entry_get_next_dylibloader_wrapper_libudev)(struct udev_list_entry*); +struct udev_list_entry* (*udev_list_entry_get_by_name_dylibloader_wrapper_libudev)(struct udev_list_entry*,const char*); +const char* (*udev_list_entry_get_name_dylibloader_wrapper_libudev)(struct udev_list_entry*); +const char* (*udev_list_entry_get_value_dylibloader_wrapper_libudev)(struct udev_list_entry*); +struct udev_device* (*udev_device_ref_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_device* (*udev_device_unref_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev* (*udev_device_get_udev_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_device* (*udev_device_new_from_syspath_dylibloader_wrapper_libudev)(struct udev*,const char*); +struct udev_device* (*udev_device_new_from_devnum_dylibloader_wrapper_libudev)(struct udev*, char, dev_t); +struct udev_device* (*udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev)(struct udev*,const char*,const char*); +struct udev_device* (*udev_device_new_from_device_id_dylibloader_wrapper_libudev)(struct udev*,const char*); +struct udev_device* (*udev_device_new_from_environment_dylibloader_wrapper_libudev)(struct udev*); +struct udev_device* (*udev_device_get_parent_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_device* (*udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*); +const char* (*udev_device_get_devpath_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_subsystem_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_devtype_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_syspath_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_sysname_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_sysnum_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_devnode_dylibloader_wrapper_libudev)(struct udev_device*); +int (*udev_device_get_is_initialized_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_list_entry* (*udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_list_entry* (*udev_device_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_list_entry* (*udev_device_get_tags_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +struct udev_list_entry* (*udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_property_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +const char* (*udev_device_get_driver_dylibloader_wrapper_libudev)(struct udev_device*); +dev_t (*udev_device_get_devnum_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_action_dylibloader_wrapper_libudev)(struct udev_device*); +unsigned long long int (*udev_device_get_seqnum_dylibloader_wrapper_libudev)(struct udev_device*); +unsigned long long int (*udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev)(struct udev_device*); +const char* (*udev_device_get_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +int (*udev_device_set_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*); +int (*udev_device_has_tag_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +struct udev_monitor* (*udev_monitor_ref_dylibloader_wrapper_libudev)(struct udev_monitor*); +struct udev_monitor* (*udev_monitor_unref_dylibloader_wrapper_libudev)(struct udev_monitor*); +struct udev* (*udev_monitor_get_udev_dylibloader_wrapper_libudev)(struct udev_monitor*); +struct udev_monitor* (*udev_monitor_new_from_netlink_dylibloader_wrapper_libudev)(struct udev*,const char*); +int (*udev_monitor_enable_receiving_dylibloader_wrapper_libudev)(struct udev_monitor*); +int (*udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev)(struct udev_monitor*, int); +int (*udev_monitor_get_fd_dylibloader_wrapper_libudev)(struct udev_monitor*); +struct udev_device* (*udev_monitor_receive_device_dylibloader_wrapper_libudev)(struct udev_monitor*); +int (*udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*,const char*); +int (*udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*); +int (*udev_monitor_filter_update_dylibloader_wrapper_libudev)(struct udev_monitor*); +int (*udev_monitor_filter_remove_dylibloader_wrapper_libudev)(struct udev_monitor*); +struct udev_enumerate* (*udev_enumerate_ref_dylibloader_wrapper_libudev)(struct udev_enumerate*); +struct udev_enumerate* (*udev_enumerate_unref_dylibloader_wrapper_libudev)(struct udev_enumerate*); +struct udev* (*udev_enumerate_get_udev_dylibloader_wrapper_libudev)(struct udev_enumerate*); +struct udev_enumerate* (*udev_enumerate_new_dylibloader_wrapper_libudev)(struct udev*); +int (*udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +int (*udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +int (*udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +int (*udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +int (*udev_enumerate_add_match_property_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +int (*udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +int (*udev_enumerate_add_match_tag_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +int (*udev_enumerate_add_match_parent_dylibloader_wrapper_libudev)(struct udev_enumerate*,struct udev_device*); +int (*udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev)(struct udev_enumerate*); +int (*udev_enumerate_add_syspath_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +int (*udev_enumerate_scan_devices_dylibloader_wrapper_libudev)(struct udev_enumerate*); +int (*udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev)(struct udev_enumerate*); +struct udev_list_entry* (*udev_enumerate_get_list_entry_dylibloader_wrapper_libudev)(struct udev_enumerate*); +struct udev_queue* (*udev_queue_ref_dylibloader_wrapper_libudev)(struct udev_queue*); +struct udev_queue* (*udev_queue_unref_dylibloader_wrapper_libudev)(struct udev_queue*); +struct udev* (*udev_queue_get_udev_dylibloader_wrapper_libudev)(struct udev_queue*); +struct udev_queue* (*udev_queue_new_dylibloader_wrapper_libudev)(struct udev*); +unsigned long long int (*udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*); +unsigned long long int (*udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*); +int (*udev_queue_get_udev_is_active_dylibloader_wrapper_libudev)(struct udev_queue*); +int (*udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev)(struct udev_queue*); +int (*udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int); +int (*udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int, unsigned long long int); +int (*udev_queue_get_fd_dylibloader_wrapper_libudev)(struct udev_queue*); +int (*udev_queue_flush_dylibloader_wrapper_libudev)(struct udev_queue*); +struct udev_list_entry* (*udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev)(struct udev_queue*); +struct udev_hwdb* (*udev_hwdb_new_dylibloader_wrapper_libudev)(struct udev*); +struct udev_hwdb* (*udev_hwdb_ref_dylibloader_wrapper_libudev)(struct udev_hwdb*); +struct udev_hwdb* (*udev_hwdb_unref_dylibloader_wrapper_libudev)(struct udev_hwdb*); +struct udev_list_entry* (*udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_hwdb*,const char*, unsigned); +int (*udev_util_encode_string_dylibloader_wrapper_libudev)(const char*, char*, size_t); +int initialize_libudev(int verbose) { + void *handle; + char *error; + handle = dlopen("libudev.so.1", RTLD_LAZY); + if (!handle) { + if (verbose) { + fprintf(stderr, "%s\n", dlerror()); + } + return(1); + } + dlerror(); +// udev_ref + *(void **) (&udev_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_unref + *(void **) (&udev_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_new + *(void **) (&udev_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_set_log_fn + *(void **) (&udev_set_log_fn_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_log_fn"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_get_log_priority + *(void **) (&udev_get_log_priority_dylibloader_wrapper_libudev) = dlsym(handle, "udev_get_log_priority"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_set_log_priority + *(void **) (&udev_set_log_priority_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_log_priority"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_get_userdata + *(void **) (&udev_get_userdata_dylibloader_wrapper_libudev) = dlsym(handle, "udev_get_userdata"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_set_userdata + *(void **) (&udev_set_userdata_dylibloader_wrapper_libudev) = dlsym(handle, "udev_set_userdata"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_list_entry_get_next + *(void **) (&udev_list_entry_get_next_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_next"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_list_entry_get_by_name + *(void **) (&udev_list_entry_get_by_name_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_by_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_list_entry_get_name + *(void **) (&udev_list_entry_get_name_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_name"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_list_entry_get_value + *(void **) (&udev_list_entry_get_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_list_entry_get_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_ref + *(void **) (&udev_device_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_unref + *(void **) (&udev_device_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_udev + *(void **) (&udev_device_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_udev"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_new_from_syspath + *(void **) (&udev_device_new_from_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_syspath"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_new_from_devnum + *(void **) (&udev_device_new_from_devnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_devnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_new_from_subsystem_sysname + *(void **) (&udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_subsystem_sysname"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_new_from_device_id + *(void **) (&udev_device_new_from_device_id_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_device_id"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_new_from_environment + *(void **) (&udev_device_new_from_environment_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_new_from_environment"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_parent + *(void **) (&udev_device_get_parent_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_parent"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_parent_with_subsystem_devtype + *(void **) (&udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_parent_with_subsystem_devtype"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_devpath + *(void **) (&udev_device_get_devpath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devpath"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_subsystem + *(void **) (&udev_device_get_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_subsystem"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_devtype + *(void **) (&udev_device_get_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devtype"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_syspath + *(void **) (&udev_device_get_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_syspath"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_sysname + *(void **) (&udev_device_get_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysname"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_sysnum + *(void **) (&udev_device_get_sysnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_devnode + *(void **) (&udev_device_get_devnode_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devnode"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_is_initialized + *(void **) (&udev_device_get_is_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_is_initialized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_devlinks_list_entry + *(void **) (&udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devlinks_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_properties_list_entry + *(void **) (&udev_device_get_properties_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_properties_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_tags_list_entry + *(void **) (&udev_device_get_tags_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_tags_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_sysattr_list_entry + *(void **) (&udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysattr_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_property_value + *(void **) (&udev_device_get_property_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_property_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_driver + *(void **) (&udev_device_get_driver_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_driver"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_devnum + *(void **) (&udev_device_get_devnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_devnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_action + *(void **) (&udev_device_get_action_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_action"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_seqnum + *(void **) (&udev_device_get_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_seqnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_usec_since_initialized + *(void **) (&udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_usec_since_initialized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_get_sysattr_value + *(void **) (&udev_device_get_sysattr_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_get_sysattr_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_set_sysattr_value + *(void **) (&udev_device_set_sysattr_value_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_set_sysattr_value"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_device_has_tag + *(void **) (&udev_device_has_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_device_has_tag"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_ref + *(void **) (&udev_monitor_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_unref + *(void **) (&udev_monitor_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_get_udev + *(void **) (&udev_monitor_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_get_udev"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_new_from_netlink + *(void **) (&udev_monitor_new_from_netlink_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_new_from_netlink"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_enable_receiving + *(void **) (&udev_monitor_enable_receiving_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_enable_receiving"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_set_receive_buffer_size + *(void **) (&udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_set_receive_buffer_size"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_get_fd + *(void **) (&udev_monitor_get_fd_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_get_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_receive_device + *(void **) (&udev_monitor_receive_device_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_receive_device"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_filter_add_match_subsystem_devtype + *(void **) (&udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_add_match_subsystem_devtype"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_filter_add_match_tag + *(void **) (&udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_add_match_tag"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_filter_update + *(void **) (&udev_monitor_filter_update_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_update"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_monitor_filter_remove + *(void **) (&udev_monitor_filter_remove_dylibloader_wrapper_libudev) = dlsym(handle, "udev_monitor_filter_remove"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_ref + *(void **) (&udev_enumerate_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_unref + *(void **) (&udev_enumerate_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_get_udev + *(void **) (&udev_enumerate_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_get_udev"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_new + *(void **) (&udev_enumerate_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_subsystem + *(void **) (&udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_subsystem"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_nomatch_subsystem + *(void **) (&udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_nomatch_subsystem"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_sysattr + *(void **) (&udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_sysattr"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_nomatch_sysattr + *(void **) (&udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_nomatch_sysattr"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_property + *(void **) (&udev_enumerate_add_match_property_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_property"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_sysname + *(void **) (&udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_sysname"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_tag + *(void **) (&udev_enumerate_add_match_tag_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_tag"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_parent + *(void **) (&udev_enumerate_add_match_parent_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_parent"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_match_is_initialized + *(void **) (&udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_match_is_initialized"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_add_syspath + *(void **) (&udev_enumerate_add_syspath_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_add_syspath"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_scan_devices + *(void **) (&udev_enumerate_scan_devices_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_scan_devices"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_scan_subsystems + *(void **) (&udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_scan_subsystems"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_enumerate_get_list_entry + *(void **) (&udev_enumerate_get_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_enumerate_get_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_ref + *(void **) (&udev_queue_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_unref + *(void **) (&udev_queue_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_udev + *(void **) (&udev_queue_get_udev_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_new + *(void **) (&udev_queue_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_kernel_seqnum + *(void **) (&udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_kernel_seqnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_udev_seqnum + *(void **) (&udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev_seqnum"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_udev_is_active + *(void **) (&udev_queue_get_udev_is_active_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_udev_is_active"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_queue_is_empty + *(void **) (&udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_queue_is_empty"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_seqnum_is_finished + *(void **) (&udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_seqnum_is_finished"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_seqnum_sequence_is_finished + *(void **) (&udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_seqnum_sequence_is_finished"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_fd + *(void **) (&udev_queue_get_fd_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_fd"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_flush + *(void **) (&udev_queue_flush_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_flush"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_queue_get_queued_list_entry + *(void **) (&udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_queue_get_queued_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_hwdb_new + *(void **) (&udev_hwdb_new_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_new"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_hwdb_ref + *(void **) (&udev_hwdb_ref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_ref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_hwdb_unref + *(void **) (&udev_hwdb_unref_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_unref"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_hwdb_get_properties_list_entry + *(void **) (&udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev) = dlsym(handle, "udev_hwdb_get_properties_list_entry"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +// udev_util_encode_string + *(void **) (&udev_util_encode_string_dylibloader_wrapper_libudev) = dlsym(handle, "udev_util_encode_string"); + if (verbose) { + error = dlerror(); + if (error != NULL) { + fprintf(stderr, "%s\n", error); + } + } +return 0; +} diff --git a/platform/linuxbsd/libudev-so_wrap.h b/platform/linuxbsd/libudev-so_wrap.h new file mode 100644 index 0000000000..dd43fd1191 --- /dev/null +++ b/platform/linuxbsd/libudev-so_wrap.h @@ -0,0 +1,378 @@ +#ifndef DYLIBLOAD_WRAPPER_LIBUDEV +#define DYLIBLOAD_WRAPPER_LIBUDEV +// This file is generated. Do not edit! +// see https://github.com/hpvb/dynload-wrapper for details +// generated by /home/hp/Projects/godot/pulse/generate-wrapper.py 0.3 on 2021-02-20 00:08:59 +// flags: /home/hp/Projects/godot/pulse/generate-wrapper.py --include /usr/include/libudev.h --sys-include <libudev.h> --soname libudev.so.1 --init-name libudev --omit-prefix gnu_ --output-header libudev-so_wrap.h --output-implementation libudev-so_wrap.c +// +#include <stdint.h> + +#define udev_ref udev_ref_dylibloader_orig_libudev +#define udev_unref udev_unref_dylibloader_orig_libudev +#define udev_new udev_new_dylibloader_orig_libudev +#define udev_set_log_fn udev_set_log_fn_dylibloader_orig_libudev +#define udev_get_log_priority udev_get_log_priority_dylibloader_orig_libudev +#define udev_set_log_priority udev_set_log_priority_dylibloader_orig_libudev +#define udev_get_userdata udev_get_userdata_dylibloader_orig_libudev +#define udev_set_userdata udev_set_userdata_dylibloader_orig_libudev +#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_orig_libudev +#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_orig_libudev +#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_orig_libudev +#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_orig_libudev +#define udev_device_ref udev_device_ref_dylibloader_orig_libudev +#define udev_device_unref udev_device_unref_dylibloader_orig_libudev +#define udev_device_get_udev udev_device_get_udev_dylibloader_orig_libudev +#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_orig_libudev +#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_orig_libudev +#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_orig_libudev +#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_orig_libudev +#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_orig_libudev +#define udev_device_get_parent udev_device_get_parent_dylibloader_orig_libudev +#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_orig_libudev +#define udev_device_get_devpath udev_device_get_devpath_dylibloader_orig_libudev +#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_orig_libudev +#define udev_device_get_devtype udev_device_get_devtype_dylibloader_orig_libudev +#define udev_device_get_syspath udev_device_get_syspath_dylibloader_orig_libudev +#define udev_device_get_sysname udev_device_get_sysname_dylibloader_orig_libudev +#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_orig_libudev +#define udev_device_get_devnode udev_device_get_devnode_dylibloader_orig_libudev +#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_orig_libudev +#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_orig_libudev +#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_orig_libudev +#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_orig_libudev +#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_orig_libudev +#define udev_device_get_property_value udev_device_get_property_value_dylibloader_orig_libudev +#define udev_device_get_driver udev_device_get_driver_dylibloader_orig_libudev +#define udev_device_get_devnum udev_device_get_devnum_dylibloader_orig_libudev +#define udev_device_get_action udev_device_get_action_dylibloader_orig_libudev +#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_orig_libudev +#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_orig_libudev +#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_orig_libudev +#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_orig_libudev +#define udev_device_has_tag udev_device_has_tag_dylibloader_orig_libudev +#define udev_monitor_ref udev_monitor_ref_dylibloader_orig_libudev +#define udev_monitor_unref udev_monitor_unref_dylibloader_orig_libudev +#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_orig_libudev +#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_orig_libudev +#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_orig_libudev +#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_orig_libudev +#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_orig_libudev +#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_orig_libudev +#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_orig_libudev +#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_orig_libudev +#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_orig_libudev +#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_orig_libudev +#define udev_enumerate_ref udev_enumerate_ref_dylibloader_orig_libudev +#define udev_enumerate_unref udev_enumerate_unref_dylibloader_orig_libudev +#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_orig_libudev +#define udev_enumerate_new udev_enumerate_new_dylibloader_orig_libudev +#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_orig_libudev +#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_orig_libudev +#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_orig_libudev +#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_orig_libudev +#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_orig_libudev +#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_orig_libudev +#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_orig_libudev +#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_orig_libudev +#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_orig_libudev +#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_orig_libudev +#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_orig_libudev +#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_orig_libudev +#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_orig_libudev +#define udev_queue_ref udev_queue_ref_dylibloader_orig_libudev +#define udev_queue_unref udev_queue_unref_dylibloader_orig_libudev +#define udev_queue_get_udev udev_queue_get_udev_dylibloader_orig_libudev +#define udev_queue_new udev_queue_new_dylibloader_orig_libudev +#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_orig_libudev +#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_orig_libudev +#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_orig_libudev +#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_orig_libudev +#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_orig_libudev +#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_orig_libudev +#define udev_queue_get_fd udev_queue_get_fd_dylibloader_orig_libudev +#define udev_queue_flush udev_queue_flush_dylibloader_orig_libudev +#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_orig_libudev +#define udev_hwdb_new udev_hwdb_new_dylibloader_orig_libudev +#define udev_hwdb_ref udev_hwdb_ref_dylibloader_orig_libudev +#define udev_hwdb_unref udev_hwdb_unref_dylibloader_orig_libudev +#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_orig_libudev +#define udev_util_encode_string udev_util_encode_string_dylibloader_orig_libudev +#include <libudev.h> +#undef udev_ref +#undef udev_unref +#undef udev_new +#undef udev_set_log_fn +#undef udev_get_log_priority +#undef udev_set_log_priority +#undef udev_get_userdata +#undef udev_set_userdata +#undef udev_list_entry_get_next +#undef udev_list_entry_get_by_name +#undef udev_list_entry_get_name +#undef udev_list_entry_get_value +#undef udev_device_ref +#undef udev_device_unref +#undef udev_device_get_udev +#undef udev_device_new_from_syspath +#undef udev_device_new_from_devnum +#undef udev_device_new_from_subsystem_sysname +#undef udev_device_new_from_device_id +#undef udev_device_new_from_environment +#undef udev_device_get_parent +#undef udev_device_get_parent_with_subsystem_devtype +#undef udev_device_get_devpath +#undef udev_device_get_subsystem +#undef udev_device_get_devtype +#undef udev_device_get_syspath +#undef udev_device_get_sysname +#undef udev_device_get_sysnum +#undef udev_device_get_devnode +#undef udev_device_get_is_initialized +#undef udev_device_get_devlinks_list_entry +#undef udev_device_get_properties_list_entry +#undef udev_device_get_tags_list_entry +#undef udev_device_get_sysattr_list_entry +#undef udev_device_get_property_value +#undef udev_device_get_driver +#undef udev_device_get_devnum +#undef udev_device_get_action +#undef udev_device_get_seqnum +#undef udev_device_get_usec_since_initialized +#undef udev_device_get_sysattr_value +#undef udev_device_set_sysattr_value +#undef udev_device_has_tag +#undef udev_monitor_ref +#undef udev_monitor_unref +#undef udev_monitor_get_udev +#undef udev_monitor_new_from_netlink +#undef udev_monitor_enable_receiving +#undef udev_monitor_set_receive_buffer_size +#undef udev_monitor_get_fd +#undef udev_monitor_receive_device +#undef udev_monitor_filter_add_match_subsystem_devtype +#undef udev_monitor_filter_add_match_tag +#undef udev_monitor_filter_update +#undef udev_monitor_filter_remove +#undef udev_enumerate_ref +#undef udev_enumerate_unref +#undef udev_enumerate_get_udev +#undef udev_enumerate_new +#undef udev_enumerate_add_match_subsystem +#undef udev_enumerate_add_nomatch_subsystem +#undef udev_enumerate_add_match_sysattr +#undef udev_enumerate_add_nomatch_sysattr +#undef udev_enumerate_add_match_property +#undef udev_enumerate_add_match_sysname +#undef udev_enumerate_add_match_tag +#undef udev_enumerate_add_match_parent +#undef udev_enumerate_add_match_is_initialized +#undef udev_enumerate_add_syspath +#undef udev_enumerate_scan_devices +#undef udev_enumerate_scan_subsystems +#undef udev_enumerate_get_list_entry +#undef udev_queue_ref +#undef udev_queue_unref +#undef udev_queue_get_udev +#undef udev_queue_new +#undef udev_queue_get_kernel_seqnum +#undef udev_queue_get_udev_seqnum +#undef udev_queue_get_udev_is_active +#undef udev_queue_get_queue_is_empty +#undef udev_queue_get_seqnum_is_finished +#undef udev_queue_get_seqnum_sequence_is_finished +#undef udev_queue_get_fd +#undef udev_queue_flush +#undef udev_queue_get_queued_list_entry +#undef udev_hwdb_new +#undef udev_hwdb_ref +#undef udev_hwdb_unref +#undef udev_hwdb_get_properties_list_entry +#undef udev_util_encode_string +#ifdef __cplusplus +extern "C" { +#endif +#define udev_ref udev_ref_dylibloader_wrapper_libudev +#define udev_unref udev_unref_dylibloader_wrapper_libudev +#define udev_new udev_new_dylibloader_wrapper_libudev +#define udev_set_log_fn udev_set_log_fn_dylibloader_wrapper_libudev +#define udev_get_log_priority udev_get_log_priority_dylibloader_wrapper_libudev +#define udev_set_log_priority udev_set_log_priority_dylibloader_wrapper_libudev +#define udev_get_userdata udev_get_userdata_dylibloader_wrapper_libudev +#define udev_set_userdata udev_set_userdata_dylibloader_wrapper_libudev +#define udev_list_entry_get_next udev_list_entry_get_next_dylibloader_wrapper_libudev +#define udev_list_entry_get_by_name udev_list_entry_get_by_name_dylibloader_wrapper_libudev +#define udev_list_entry_get_name udev_list_entry_get_name_dylibloader_wrapper_libudev +#define udev_list_entry_get_value udev_list_entry_get_value_dylibloader_wrapper_libudev +#define udev_device_ref udev_device_ref_dylibloader_wrapper_libudev +#define udev_device_unref udev_device_unref_dylibloader_wrapper_libudev +#define udev_device_get_udev udev_device_get_udev_dylibloader_wrapper_libudev +#define udev_device_new_from_syspath udev_device_new_from_syspath_dylibloader_wrapper_libudev +#define udev_device_new_from_devnum udev_device_new_from_devnum_dylibloader_wrapper_libudev +#define udev_device_new_from_subsystem_sysname udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev +#define udev_device_new_from_device_id udev_device_new_from_device_id_dylibloader_wrapper_libudev +#define udev_device_new_from_environment udev_device_new_from_environment_dylibloader_wrapper_libudev +#define udev_device_get_parent udev_device_get_parent_dylibloader_wrapper_libudev +#define udev_device_get_parent_with_subsystem_devtype udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev +#define udev_device_get_devpath udev_device_get_devpath_dylibloader_wrapper_libudev +#define udev_device_get_subsystem udev_device_get_subsystem_dylibloader_wrapper_libudev +#define udev_device_get_devtype udev_device_get_devtype_dylibloader_wrapper_libudev +#define udev_device_get_syspath udev_device_get_syspath_dylibloader_wrapper_libudev +#define udev_device_get_sysname udev_device_get_sysname_dylibloader_wrapper_libudev +#define udev_device_get_sysnum udev_device_get_sysnum_dylibloader_wrapper_libudev +#define udev_device_get_devnode udev_device_get_devnode_dylibloader_wrapper_libudev +#define udev_device_get_is_initialized udev_device_get_is_initialized_dylibloader_wrapper_libudev +#define udev_device_get_devlinks_list_entry udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev +#define udev_device_get_properties_list_entry udev_device_get_properties_list_entry_dylibloader_wrapper_libudev +#define udev_device_get_tags_list_entry udev_device_get_tags_list_entry_dylibloader_wrapper_libudev +#define udev_device_get_sysattr_list_entry udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev +#define udev_device_get_property_value udev_device_get_property_value_dylibloader_wrapper_libudev +#define udev_device_get_driver udev_device_get_driver_dylibloader_wrapper_libudev +#define udev_device_get_devnum udev_device_get_devnum_dylibloader_wrapper_libudev +#define udev_device_get_action udev_device_get_action_dylibloader_wrapper_libudev +#define udev_device_get_seqnum udev_device_get_seqnum_dylibloader_wrapper_libudev +#define udev_device_get_usec_since_initialized udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev +#define udev_device_get_sysattr_value udev_device_get_sysattr_value_dylibloader_wrapper_libudev +#define udev_device_set_sysattr_value udev_device_set_sysattr_value_dylibloader_wrapper_libudev +#define udev_device_has_tag udev_device_has_tag_dylibloader_wrapper_libudev +#define udev_monitor_ref udev_monitor_ref_dylibloader_wrapper_libudev +#define udev_monitor_unref udev_monitor_unref_dylibloader_wrapper_libudev +#define udev_monitor_get_udev udev_monitor_get_udev_dylibloader_wrapper_libudev +#define udev_monitor_new_from_netlink udev_monitor_new_from_netlink_dylibloader_wrapper_libudev +#define udev_monitor_enable_receiving udev_monitor_enable_receiving_dylibloader_wrapper_libudev +#define udev_monitor_set_receive_buffer_size udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev +#define udev_monitor_get_fd udev_monitor_get_fd_dylibloader_wrapper_libudev +#define udev_monitor_receive_device udev_monitor_receive_device_dylibloader_wrapper_libudev +#define udev_monitor_filter_add_match_subsystem_devtype udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev +#define udev_monitor_filter_add_match_tag udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev +#define udev_monitor_filter_update udev_monitor_filter_update_dylibloader_wrapper_libudev +#define udev_monitor_filter_remove udev_monitor_filter_remove_dylibloader_wrapper_libudev +#define udev_enumerate_ref udev_enumerate_ref_dylibloader_wrapper_libudev +#define udev_enumerate_unref udev_enumerate_unref_dylibloader_wrapper_libudev +#define udev_enumerate_get_udev udev_enumerate_get_udev_dylibloader_wrapper_libudev +#define udev_enumerate_new udev_enumerate_new_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_subsystem udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev +#define udev_enumerate_add_nomatch_subsystem udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_sysattr udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev +#define udev_enumerate_add_nomatch_sysattr udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_property udev_enumerate_add_match_property_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_sysname udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_tag udev_enumerate_add_match_tag_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_parent udev_enumerate_add_match_parent_dylibloader_wrapper_libudev +#define udev_enumerate_add_match_is_initialized udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev +#define udev_enumerate_add_syspath udev_enumerate_add_syspath_dylibloader_wrapper_libudev +#define udev_enumerate_scan_devices udev_enumerate_scan_devices_dylibloader_wrapper_libudev +#define udev_enumerate_scan_subsystems udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev +#define udev_enumerate_get_list_entry udev_enumerate_get_list_entry_dylibloader_wrapper_libudev +#define udev_queue_ref udev_queue_ref_dylibloader_wrapper_libudev +#define udev_queue_unref udev_queue_unref_dylibloader_wrapper_libudev +#define udev_queue_get_udev udev_queue_get_udev_dylibloader_wrapper_libudev +#define udev_queue_new udev_queue_new_dylibloader_wrapper_libudev +#define udev_queue_get_kernel_seqnum udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev +#define udev_queue_get_udev_seqnum udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev +#define udev_queue_get_udev_is_active udev_queue_get_udev_is_active_dylibloader_wrapper_libudev +#define udev_queue_get_queue_is_empty udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev +#define udev_queue_get_seqnum_is_finished udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev +#define udev_queue_get_seqnum_sequence_is_finished udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev +#define udev_queue_get_fd udev_queue_get_fd_dylibloader_wrapper_libudev +#define udev_queue_flush udev_queue_flush_dylibloader_wrapper_libudev +#define udev_queue_get_queued_list_entry udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev +#define udev_hwdb_new udev_hwdb_new_dylibloader_wrapper_libudev +#define udev_hwdb_ref udev_hwdb_ref_dylibloader_wrapper_libudev +#define udev_hwdb_unref udev_hwdb_unref_dylibloader_wrapper_libudev +#define udev_hwdb_get_properties_list_entry udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev +#define udev_util_encode_string udev_util_encode_string_dylibloader_wrapper_libudev +extern struct udev* (*udev_ref_dylibloader_wrapper_libudev)(struct udev*); +extern struct udev* (*udev_unref_dylibloader_wrapper_libudev)(struct udev*); +extern struct udev* (*udev_new_dylibloader_wrapper_libudev)( void); +extern void (*udev_set_log_fn_dylibloader_wrapper_libudev)(struct udev*, void*); +extern int (*udev_get_log_priority_dylibloader_wrapper_libudev)(struct udev*); +extern void (*udev_set_log_priority_dylibloader_wrapper_libudev)(struct udev*, int); +extern void* (*udev_get_userdata_dylibloader_wrapper_libudev)(struct udev*); +extern void (*udev_set_userdata_dylibloader_wrapper_libudev)(struct udev*, void*); +extern struct udev_list_entry* (*udev_list_entry_get_next_dylibloader_wrapper_libudev)(struct udev_list_entry*); +extern struct udev_list_entry* (*udev_list_entry_get_by_name_dylibloader_wrapper_libudev)(struct udev_list_entry*,const char*); +extern const char* (*udev_list_entry_get_name_dylibloader_wrapper_libudev)(struct udev_list_entry*); +extern const char* (*udev_list_entry_get_value_dylibloader_wrapper_libudev)(struct udev_list_entry*); +extern struct udev_device* (*udev_device_ref_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_device* (*udev_device_unref_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev* (*udev_device_get_udev_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_device* (*udev_device_new_from_syspath_dylibloader_wrapper_libudev)(struct udev*,const char*); +extern struct udev_device* (*udev_device_new_from_devnum_dylibloader_wrapper_libudev)(struct udev*, char, dev_t); +extern struct udev_device* (*udev_device_new_from_subsystem_sysname_dylibloader_wrapper_libudev)(struct udev*,const char*,const char*); +extern struct udev_device* (*udev_device_new_from_device_id_dylibloader_wrapper_libudev)(struct udev*,const char*); +extern struct udev_device* (*udev_device_new_from_environment_dylibloader_wrapper_libudev)(struct udev*); +extern struct udev_device* (*udev_device_get_parent_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_device* (*udev_device_get_parent_with_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*); +extern const char* (*udev_device_get_devpath_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_subsystem_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_devtype_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_syspath_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_sysname_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_sysnum_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_devnode_dylibloader_wrapper_libudev)(struct udev_device*); +extern int (*udev_device_get_is_initialized_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_list_entry* (*udev_device_get_devlinks_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_list_entry* (*udev_device_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_list_entry* (*udev_device_get_tags_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +extern struct udev_list_entry* (*udev_device_get_sysattr_list_entry_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_property_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +extern const char* (*udev_device_get_driver_dylibloader_wrapper_libudev)(struct udev_device*); +extern dev_t (*udev_device_get_devnum_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_action_dylibloader_wrapper_libudev)(struct udev_device*); +extern unsigned long long int (*udev_device_get_seqnum_dylibloader_wrapper_libudev)(struct udev_device*); +extern unsigned long long int (*udev_device_get_usec_since_initialized_dylibloader_wrapper_libudev)(struct udev_device*); +extern const char* (*udev_device_get_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +extern int (*udev_device_set_sysattr_value_dylibloader_wrapper_libudev)(struct udev_device*,const char*,const char*); +extern int (*udev_device_has_tag_dylibloader_wrapper_libudev)(struct udev_device*,const char*); +extern struct udev_monitor* (*udev_monitor_ref_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern struct udev_monitor* (*udev_monitor_unref_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern struct udev* (*udev_monitor_get_udev_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern struct udev_monitor* (*udev_monitor_new_from_netlink_dylibloader_wrapper_libudev)(struct udev*,const char*); +extern int (*udev_monitor_enable_receiving_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern int (*udev_monitor_set_receive_buffer_size_dylibloader_wrapper_libudev)(struct udev_monitor*, int); +extern int (*udev_monitor_get_fd_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern struct udev_device* (*udev_monitor_receive_device_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern int (*udev_monitor_filter_add_match_subsystem_devtype_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*,const char*); +extern int (*udev_monitor_filter_add_match_tag_dylibloader_wrapper_libudev)(struct udev_monitor*,const char*); +extern int (*udev_monitor_filter_update_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern int (*udev_monitor_filter_remove_dylibloader_wrapper_libudev)(struct udev_monitor*); +extern struct udev_enumerate* (*udev_enumerate_ref_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern struct udev_enumerate* (*udev_enumerate_unref_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern struct udev* (*udev_enumerate_get_udev_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern struct udev_enumerate* (*udev_enumerate_new_dylibloader_wrapper_libudev)(struct udev*); +extern int (*udev_enumerate_add_match_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +extern int (*udev_enumerate_add_nomatch_subsystem_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +extern int (*udev_enumerate_add_match_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +extern int (*udev_enumerate_add_nomatch_sysattr_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +extern int (*udev_enumerate_add_match_property_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*,const char*); +extern int (*udev_enumerate_add_match_sysname_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +extern int (*udev_enumerate_add_match_tag_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +extern int (*udev_enumerate_add_match_parent_dylibloader_wrapper_libudev)(struct udev_enumerate*,struct udev_device*); +extern int (*udev_enumerate_add_match_is_initialized_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern int (*udev_enumerate_add_syspath_dylibloader_wrapper_libudev)(struct udev_enumerate*,const char*); +extern int (*udev_enumerate_scan_devices_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern int (*udev_enumerate_scan_subsystems_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern struct udev_list_entry* (*udev_enumerate_get_list_entry_dylibloader_wrapper_libudev)(struct udev_enumerate*); +extern struct udev_queue* (*udev_queue_ref_dylibloader_wrapper_libudev)(struct udev_queue*); +extern struct udev_queue* (*udev_queue_unref_dylibloader_wrapper_libudev)(struct udev_queue*); +extern struct udev* (*udev_queue_get_udev_dylibloader_wrapper_libudev)(struct udev_queue*); +extern struct udev_queue* (*udev_queue_new_dylibloader_wrapper_libudev)(struct udev*); +extern unsigned long long int (*udev_queue_get_kernel_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*); +extern unsigned long long int (*udev_queue_get_udev_seqnum_dylibloader_wrapper_libudev)(struct udev_queue*); +extern int (*udev_queue_get_udev_is_active_dylibloader_wrapper_libudev)(struct udev_queue*); +extern int (*udev_queue_get_queue_is_empty_dylibloader_wrapper_libudev)(struct udev_queue*); +extern int (*udev_queue_get_seqnum_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int); +extern int (*udev_queue_get_seqnum_sequence_is_finished_dylibloader_wrapper_libudev)(struct udev_queue*, unsigned long long int, unsigned long long int); +extern int (*udev_queue_get_fd_dylibloader_wrapper_libudev)(struct udev_queue*); +extern int (*udev_queue_flush_dylibloader_wrapper_libudev)(struct udev_queue*); +extern struct udev_list_entry* (*udev_queue_get_queued_list_entry_dylibloader_wrapper_libudev)(struct udev_queue*); +extern struct udev_hwdb* (*udev_hwdb_new_dylibloader_wrapper_libudev)(struct udev*); +extern struct udev_hwdb* (*udev_hwdb_ref_dylibloader_wrapper_libudev)(struct udev_hwdb*); +extern struct udev_hwdb* (*udev_hwdb_unref_dylibloader_wrapper_libudev)(struct udev_hwdb*); +extern struct udev_list_entry* (*udev_hwdb_get_properties_list_entry_dylibloader_wrapper_libudev)(struct udev_hwdb*,const char*, unsigned); +extern int (*udev_util_encode_string_dylibloader_wrapper_libudev)(const char*, char*, size_t); +int initialize_libudev(int verbose); +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linuxbsd/os_linuxbsd.cpp b/platform/linuxbsd/os_linuxbsd.cpp index e00a32e3ba..69474c6dec 100644 --- a/platform/linuxbsd/os_linuxbsd.cpp +++ b/platform/linuxbsd/os_linuxbsd.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,7 +30,7 @@ #include "os_linuxbsd.h" -#include "core/os/dir_access.h" +#include "core/io/dir_access.h" #include "main/main.h" #ifdef X11_ENABLED @@ -51,6 +51,70 @@ #include <sys/types.h> #include <unistd.h> +void OS_LinuxBSD::alert(const String &p_alert, const String &p_title) { + const char *message_programs[] = { "zenity", "kdialog", "Xdialog", "xmessage" }; + + String path = get_environment("PATH"); + Vector<String> path_elems = path.split(":", false); + String program; + + for (int i = 0; i < path_elems.size(); i++) { + for (uint64_t k = 0; k < sizeof(message_programs) / sizeof(char *); k++) { + String tested_path = path_elems[i].plus_file(message_programs[k]); + + if (FileAccess::exists(tested_path)) { + program = tested_path; + break; + } + } + + if (program.length()) { + break; + } + } + + List<String> args; + + if (program.ends_with("zenity")) { + args.push_back("--error"); + args.push_back("--width"); + args.push_back("500"); + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--text"); + args.push_back(p_alert); + } + + if (program.ends_with("kdialog")) { + args.push_back("--error"); + args.push_back(p_alert); + args.push_back("--title"); + args.push_back(p_title); + } + + if (program.ends_with("Xdialog")) { + args.push_back("--title"); + args.push_back(p_title); + args.push_back("--msgbox"); + args.push_back(p_alert); + args.push_back("0"); + args.push_back("0"); + } + + if (program.ends_with("xmessage")) { + args.push_back("-center"); + args.push_back("-title"); + args.push_back(p_title); + args.push_back(p_alert); + } + + if (program.length()) { + execute(program, args); + } else { + print_line(p_alert); + } +} + void OS_LinuxBSD::initialize() { crash_handler.initialize(); @@ -65,9 +129,9 @@ void OS_LinuxBSD::initialize_joypads() { String OS_LinuxBSD::get_unique_id() const { static String machine_id; - if (machine_id.empty()) { + if (machine_id.is_empty()) { if (FileAccess *f = FileAccess::open("/etc/machine-id", FileAccess::READ)) { - while (machine_id.empty() && !f->eof_reached()) { + while (machine_id.is_empty() && !f->eof_reached()) { machine_id = f->get_line().strip_edges(); } f->close(); @@ -116,6 +180,8 @@ String OS_LinuxBSD::get_name() const { return "FreeBSD"; #elif defined(__NetBSD__) return "NetBSD"; +#elif defined(__OpenBSD__) + return "OpenBSD"; #else return "BSD"; #endif @@ -123,18 +189,39 @@ String OS_LinuxBSD::get_name() const { Error OS_LinuxBSD::shell_open(String p_uri) { Error ok; + int err_code; List<String> args; args.push_back(p_uri); - ok = execute("xdg-open", args, false); - if (ok == OK) { + + // Agnostic + ok = execute("xdg-open", args, nullptr, &err_code); + if (ok == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + // GNOME + args.push_front("open"); // The command is `gio open`, so we need to add it to args + ok = execute("gio", args, nullptr, &err_code); + if (ok == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + args.pop_front(); + ok = execute("gvfs-open", args, nullptr, &err_code); + if (ok == OK && !err_code) { return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; } - ok = execute("gnome-open", args, false); - if (ok == OK) { + // KDE + ok = execute("kde-open5", args, nullptr, &err_code); + if (ok == OK && !err_code) { return OK; } - ok = execute("kde-open", args, false); - return ok; + ok = execute("kde-open", args, nullptr, &err_code); + return !err_code ? ok : FAILED; } bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) { @@ -143,7 +230,12 @@ bool OS_LinuxBSD::_check_internal_feature_support(const String &p_feature) { String OS_LinuxBSD::get_config_path() const { if (has_environment("XDG_CONFIG_HOME")) { - return get_environment("XDG_CONFIG_HOME"); + if (get_environment("XDG_CONFIG_HOME").is_absolute_path()) { + return get_environment("XDG_CONFIG_HOME"); + } else { + WARN_PRINT_ONCE("`XDG_CONFIG_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.config` or `.` per the XDG Base Directory specification."); + return has_environment("HOME") ? get_environment("HOME").plus_file(".config") : "."; + } } else if (has_environment("HOME")) { return get_environment("HOME").plus_file(".config"); } else { @@ -153,7 +245,12 @@ String OS_LinuxBSD::get_config_path() const { String OS_LinuxBSD::get_data_path() const { if (has_environment("XDG_DATA_HOME")) { - return get_environment("XDG_DATA_HOME"); + if (get_environment("XDG_DATA_HOME").is_absolute_path()) { + return get_environment("XDG_DATA_HOME"); + } else { + WARN_PRINT_ONCE("`XDG_DATA_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.local/share` or `get_config_path()` per the XDG Base Directory specification."); + return has_environment("HOME") ? get_environment("HOME").plus_file(".local/share") : get_config_path(); + } } else if (has_environment("HOME")) { return get_environment("HOME").plus_file(".local/share"); } else { @@ -163,7 +260,12 @@ String OS_LinuxBSD::get_data_path() const { String OS_LinuxBSD::get_cache_path() const { if (has_environment("XDG_CACHE_HOME")) { - return get_environment("XDG_CACHE_HOME"); + if (get_environment("XDG_CACHE_HOME").is_absolute_path()) { + return get_environment("XDG_CACHE_HOME"); + } else { + WARN_PRINT_ONCE("`XDG_CACHE_HOME` is a relative path. Ignoring its value and falling back to `$HOME/.cache` or `get_config_path()` per the XDG Base Directory specification."); + return has_environment("HOME") ? get_environment("HOME").plus_file(".cache") : get_config_path(); + } } else if (has_environment("HOME")) { return get_environment("HOME").plus_file(".cache"); } else { @@ -171,7 +273,7 @@ String OS_LinuxBSD::get_cache_path() const { } } -String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const { +String OS_LinuxBSD::get_system_dir(SystemDir p_dir, bool p_shared_storage) const { String xdgparam; switch (p_dir) { @@ -211,7 +313,7 @@ String OS_LinuxBSD::get_system_dir(SystemDir p_dir) const { String pipe; List<String> arg; arg.push_back(xdgparam); - Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, true, nullptr, &pipe); + Error err = const_cast<OS_LinuxBSD *>(this)->execute("xdg-user-dir", arg, &pipe); if (err != OK) { return "."; } @@ -225,7 +327,7 @@ void OS_LinuxBSD::run() { return; } - main_loop->init(); + main_loop->initialize(); //uint64_t last_ticks=get_ticks_usec(); @@ -242,7 +344,7 @@ void OS_LinuxBSD::run() { } }; - main_loop->finish(); + main_loop->finalize(); } void OS_LinuxBSD::disable_crash_handler() { @@ -282,65 +384,150 @@ static String get_mountpoint(const String &p_path) { } Error OS_LinuxBSD::move_to_trash(const String &p_path) { - String trash_can = ""; + int err_code; + List<String> args; + args.push_back(p_path); + args.push_front("trash"); // The command is `gio trash <file_name>` so we need to add it to args. + Error result = execute("gio", args, nullptr, &err_code); // For GNOME based machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + args.pop_front(); + args.push_front("move"); + args.push_back("trash:/"); // The command is `kioclient5 move <file_name> trash:/`. + result = execute("kioclient5", args, nullptr, &err_code); // For KDE based machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + args.pop_front(); + args.pop_back(); + result = execute("gvfs-trash", args, nullptr, &err_code); // For older Linux machines. + if (result == OK && !err_code) { + return OK; + } else if (err_code == 2) { + return ERR_FILE_NOT_FOUND; + } + + // If the commands `kioclient5`, `gio` or `gvfs-trash` don't exist on the system we do it manually. + String trash_path = ""; String mnt = get_mountpoint(p_path); - // If there is a directory "[Mountpoint]/.Trash-[UID]/files", use it as the trash can. + // If there is a directory "[Mountpoint]/.Trash-[UID], use it as the trash can. if (mnt != "") { - String path(mnt + "/.Trash-" + itos(getuid()) + "/files"); + String path(mnt + "/.Trash-" + itos(getuid())); struct stat s; if (!stat(path.utf8().get_data(), &s)) { - trash_can = path; + trash_path = path; } } - // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash/files" as the trash can. - if (trash_can == "") { + // Otherwise, if ${XDG_DATA_HOME} is defined, use "${XDG_DATA_HOME}/Trash" as the trash can. + if (trash_path == "") { char *dhome = getenv("XDG_DATA_HOME"); if (dhome) { - trash_can = String(dhome) + "/Trash/files"; + trash_path = String(dhome) + "/Trash"; } } - // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash/files" as the trash can. - if (trash_can == "") { + // Otherwise, if ${HOME} is defined, use "${HOME}/.local/share/Trash" as the trash can. + if (trash_path == "") { char *home = getenv("HOME"); if (home) { - trash_can = String(home) + "/.local/share/Trash/files"; + trash_path = String(home) + "/.local/share/Trash"; } } // Issue an error if none of the previous locations is appropriate for the trash can. - if (trash_can == "") { - ERR_PRINT("move_to_trash: Could not determine the trash can location"); - return FAILED; - } + ERR_FAIL_COND_V_MSG(trash_path == "", FAILED, "Could not determine the trash can location"); // Create needed directories for decided trash can location. - DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - Error err = dir_access->make_dir_recursive(trash_can); - memdelete(dir_access); + { + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = dir_access->make_dir_recursive(trash_path); + + // Issue an error if trash can is not created properly. + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\""); + err = dir_access->make_dir_recursive(trash_path + "/files"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/files"); + err = dir_access->make_dir_recursive(trash_path + "/info"); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not create the trash path \"" + trash_path + "\"/info"); + memdelete(dir_access); + } - // Issue an error if trash can is not created proprely. - if (err != OK) { - ERR_PRINT("move_to_trash: Could not create the trash can \"" + trash_can + "\""); - return err; + // The trash can is successfully created, now we check that we don't exceed our file name length limit. + // If the file name is too long trim it so we can add the identifying number and ".trashinfo". + // Assumes that the file name length limit is 255 characters. + String file_name = p_path.get_file(); + if (file_name.length() == 0) { + file_name = p_path.get_base_dir().get_file(); + } + if (file_name.length() > 240) { + file_name = file_name.substr(0, file_name.length() - 15); } - // The trash can is successfully created, now move the given resource to it. + String dest_path = trash_path + "/files/" + file_name; + struct stat buff; + int id_number = 0; + String fn = file_name; + + // Checks if a resource with the same name already exist in the trash can, + // if there is, add an identifying number to our resource's name. + while (stat(dest_path.utf8().get_data(), &buff) == 0) { + id_number++; + + // Added a limit to check for identically named files already on the trash can + // if there are too many it could make the editor unresponsive. + ERR_FAIL_COND_V_MSG(id_number > 99, FAILED, "Too many identically named resources already in the trash can."); + fn = file_name + "." + itos(id_number); + dest_path = trash_path + "/files/" + fn; + } + file_name = fn; + + // Generates the .trashinfo file + OS::Date date = OS::get_singleton()->get_date(false); + OS::Time time = OS::get_singleton()->get_time(false); + String timestamp = vformat("%04d-%02d-%02dT%02d:%02d:", date.year, (int)date.month, date.day, time.hour, time.minute); + timestamp = vformat("%s%02d", timestamp, time.second); // vformat only supports up to 6 arguments. + String trash_info = "[Trash Info]\nPath=" + p_path.uri_encode() + "\nDeletionDate=" + timestamp + "\n"; + { + Error err; + FileAccess *file = FileAccess::open(trash_path + "/info/" + file_name + ".trashinfo", FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't create trashinfo file:" + trash_path + "/info/" + file_name + ".trashinfo"); + file->store_string(trash_info); + file->close(); + + // Rename our resource before moving it to the trash can. + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(p_path, p_path.get_base_dir() + "/" + file_name); + ERR_FAIL_COND_V_MSG(err != OK, err, "Can't rename file \"" + p_path + "\""); + memdelete(dir_access); + } + + // Move the given resource to the trash can. // Do not use DirAccess:rename() because it can't move files across multiple mountpoints. List<String> mv_args; - mv_args.push_back(p_path); - mv_args.push_back(trash_can); - int retval; - err = execute("mv", mv_args, true, nullptr, nullptr, &retval); - - // Issue an error if "mv" failed to move the given resource to the trash can. - if (err != OK || retval != 0) { - ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_can + "\""); - return FAILED; + mv_args.push_back(p_path.get_base_dir() + "/" + file_name); + mv_args.push_back(trash_path + "/files"); + { + int retval; + Error err = execute("mv", mv_args, nullptr, &retval); + + // Issue an error if "mv" failed to move the given resource to the trash can. + if (err != OK || retval != 0) { + ERR_PRINT("move_to_trash: Could not move the resource \"" + p_path + "\" to the trash can \"" + trash_path + "/files\""); + DirAccess *dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + err = dir_access->rename(p_path.get_base_dir() + "/" + file_name, p_path); + memdelete(dir_access); + ERR_FAIL_COND_V_MSG(err != OK, err, "Could not rename " + p_path.get_base_dir() + "/" + file_name + " back to its original name:" + p_path); + return FAILED; + } } - return OK; } diff --git a/platform/linuxbsd/os_linuxbsd.h b/platform/linuxbsd/os_linuxbsd.h index cd4fbd9db5..35c80e3f9b 100644 --- a/platform/linuxbsd/os_linuxbsd.h +++ b/platform/linuxbsd/os_linuxbsd.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -39,11 +39,11 @@ #include "drivers/unix/os_unix.h" #include "joypad_linux.h" #include "servers/audio_server.h" -#include "servers/rendering/rasterizer.h" +#include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" class OS_LinuxBSD : public OS_Unix { - virtual void delete_main_loop(); + virtual void delete_main_loop() override; bool force_quit; @@ -68,36 +68,38 @@ class OS_LinuxBSD : public OS_Unix { MainLoop *main_loop; protected: - virtual void initialize(); - virtual void finalize(); + virtual void initialize() override; + virtual void finalize() override; - virtual void initialize_joypads(); + virtual void initialize_joypads() override; - virtual void set_main_loop(MainLoop *p_main_loop); + virtual void set_main_loop(MainLoop *p_main_loop) override; public: - virtual String get_name() const; + virtual String get_name() const override; - virtual MainLoop *get_main_loop() const; + virtual MainLoop *get_main_loop() const override; - virtual String get_config_path() const; - virtual String get_data_path() const; - virtual String get_cache_path() const; + virtual String get_config_path() const override; + virtual String get_data_path() const override; + virtual String get_cache_path() const override; - virtual String get_system_dir(SystemDir p_dir) const; + virtual String get_system_dir(SystemDir p_dir, bool p_shared_storage = true) const override; - virtual Error shell_open(String p_uri); + virtual Error shell_open(String p_uri) override; - virtual String get_unique_id() const; + virtual String get_unique_id() const override; - virtual bool _check_internal_feature_support(const String &p_feature); + virtual void alert(const String &p_alert, const String &p_title = "ALERT!") override; + + virtual bool _check_internal_feature_support(const String &p_feature) override; void run(); - void disable_crash_handler(); - bool is_disable_crash_handler() const; + virtual void disable_crash_handler() override; + virtual bool is_disable_crash_handler() const override; - virtual Error move_to_trash(const String &p_path); + virtual Error move_to_trash(const String &p_path) override; OS_LinuxBSD(); }; diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h index 571ad03db0..aa78b48bb0 100644 --- a/platform/linuxbsd/platform_config.h +++ b/platform/linuxbsd/platform_config.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -43,3 +43,5 @@ #define PTHREAD_BSD_SET_NAME #endif #endif + +#define OPENGL_INCLUDE_H "thirdparty/glad/glad/glad.h" diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp index 2eaa9f9446..4d58e4999b 100644 --- a/platform/linuxbsd/vulkan_context_x11.cpp +++ b/platform/linuxbsd/vulkan_context_x11.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -29,13 +29,17 @@ /*************************************************************************/ #include "vulkan_context_x11.h" -#include <vulkan/vulkan_xlib.h> +#ifdef USE_VOLK +#include <volk.h> +#else +#include <vulkan/vulkan.h> +#endif const char *VulkanContextX11::_get_platform_surface_extension() const { return VK_KHR_XLIB_SURFACE_EXTENSION_NAME; } -Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { +Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height) { VkXlibSurfaceCreateInfoKHR createInfo; createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR; createInfo.pNext = nullptr; @@ -44,9 +48,9 @@ Error VulkanContextX11::window_create(DisplayServer::WindowID p_window_id, ::Win createInfo.window = p_window; VkSurfaceKHR surface; - VkResult err = vkCreateXlibSurfaceKHR(_get_instance(), &createInfo, nullptr, &surface); + VkResult err = vkCreateXlibSurfaceKHR(get_instance(), &createInfo, nullptr, &surface); ERR_FAIL_COND_V(err, ERR_CANT_CREATE); - return _window_create(p_window_id, surface, p_width, p_height); + return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height); } VulkanContextX11::VulkanContextX11() { diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h index af3d923cfe..de4a9c7b90 100644 --- a/platform/linuxbsd/vulkan_context_x11.h +++ b/platform/linuxbsd/vulkan_context_x11.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -38,7 +38,7 @@ class VulkanContextX11 : public VulkanContext { virtual const char *_get_platform_surface_extension() const; public: - Error window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height); + Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, ::Window p_window, Display *p_display, int p_width, int p_height); VulkanContextX11(); ~VulkanContextX11(); |