diff options
Diffstat (limited to 'platform/linuxbsd')
24 files changed, 2838 insertions, 751 deletions
diff --git a/platform/linuxbsd/SCsub b/platform/linuxbsd/SCsub index ae75a75830..46714e9502 100644 --- a/platform/linuxbsd/SCsub +++ b/platform/linuxbsd/SCsub @@ -16,7 +16,10 @@ common_x11 = [ "key_mapping_x11.cpp", ] +if "udev" in env and env["udev"]: + common_x11.append("libudev-so_wrap.c") + prog = env.add_program("#bin/godot", ["godot_linuxbsd.cpp"] + common_x11) -if (env["debug_symbols"] == "full" or env["debug_symbols"] == "yes") and env["separate_debug_symbols"]: +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 index 71dc9602b3..1f92370ab7 100644 --- a/platform/linuxbsd/context_gl_x11.cpp +++ b/platform/linuxbsd/context_gl_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 */ diff --git a/platform/linuxbsd/context_gl_x11.h b/platform/linuxbsd/context_gl_x11.h index 7aed280c98..d089886f4d 100644 --- a/platform/linuxbsd/context_gl_x11.h +++ b/platform/linuxbsd/context_gl_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 */ diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp index b3553e961a..ea0222cb19 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,8 @@ #include "crash_handler_linuxbsd.h" +#include "core/config/project_settings.h" #include "core/os/os.h" -#include "core/project_settings.h" #include "main/main.h" #ifdef DEBUG_ENABLED @@ -67,7 +67,7 @@ static void handle_crash(int sig) { OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_CRASH); } - fprintf(stderr, "Dumping the backtrace. %ls\n", msg.c_str()); + fprintf(stderr, "Dumping the backtrace. %s\n", msg.utf8().get_data()); char **strings = backtrace_symbols(bt_buffer, size); if (strings) { for (size_t i = 1; i < size; i++) { @@ -104,12 +104,12 @@ 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); } - fprintf(stderr, "[%ld] %s (%ls)\n", (long int)i, fname, output.c_str()); + fprintf(stderr, "[%ld] %s (%s)\n", (long int)i, fname, output.utf8().get_data()); } free(strings); 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 07fa06bc06..8f1afe0e66 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -12,7 +12,6 @@ def get_name(): def can_build(): - if os.name != "posix" or sys.platform == "darwin": return False @@ -35,6 +34,11 @@ def can_build(): print("xinerama not found.. x11 disabled.") return False + x11_error = os.system("pkg-config xext --modversion > /dev/null ") + if x11_error: + print("xext not found.. x11 disabled.") + return False + x11_error = os.system("pkg-config xrandr --modversion > /dev/null ") if x11_error: print("xrandr not found.. x11 disabled.") @@ -60,15 +64,15 @@ 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("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("udev", "Use udev for gamepad connection callbacks", 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), @@ -76,12 +80,10 @@ def get_opts(): def get_flags(): - return [] def configure(env): - ## Build type if env["target"] == "release": @@ -90,9 +92,7 @@ def configure(env): else: # 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": @@ -102,14 +102,12 @@ def configure(env): 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", "DEBUG_MEMORY_ENABLED"]) + env.Prepend(CPPDEFINES=["DEBUG_ENABLED"]) env.Append(LINKFLAGS=["-rdynamic"]) ## Architecture @@ -128,8 +126,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"]: @@ -194,6 +190,7 @@ def configure(env): env.ParseConfig("pkg-config x11 --cflags --libs") env.ParseConfig("pkg-config xcursor --cflags --libs") env.ParseConfig("pkg-config xinerama --cflags --libs") + env.ParseConfig("pkg-config xext --cflags --libs") env.ParseConfig("pkg-config xrandr --cflags --libs") env.ParseConfig("pkg-config xrender --cflags --libs") env.ParseConfig("pkg-config xi --cflags --libs") @@ -205,14 +202,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") @@ -296,9 +310,8 @@ def configure(env): 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") @@ -306,20 +319,20 @@ def configure(env): 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") 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") + else: + env["udev"] = False # Linux specific # Linkflags below this line should typically stay the last ones if not env["builtin_zlib"]: @@ -376,4 +389,13 @@ def configure(env): # Link those statically for portability if env["use_static_cpp"]: - env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"]) + # Workaround for GH-31743, Ubuntu 18.04 i386 crashes when it's used. + # That doesn't make any sense but it's likely a Ubuntu bug? + if is64 or env["bits"] == "64": + 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..da1c95a593 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 */ @@ -33,8 +33,8 @@ #include "detect_prime.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..0b548b849e 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 */ diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index ef5ac66b34..fceeb82325 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,35 +32,27 @@ #ifdef X11_ENABLED +#include "core/config/project_settings.h" +#include "core/string/print_string.h" #include "detect_prime_x11.h" - -#include "core/os/dir_access.h" -#include "core/print_string.h" -#include "errno.h" #include "key_mapping_x11.h" - -#if defined(OPENGL_ENABLED) -#include "drivers/gles2/rasterizer_gles2.h" -#endif - -#if defined(VULKAN_ENABLED) -#include "servers/rendering/rasterizer_rd/rasterizer_rd.h" -#endif - +#include "main/main.h" #include "scene/resources/texture.h" -#ifdef HAVE_MNTENT -#include <mntent.h> +#if defined(VULKAN_ENABLED) +#include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif +#include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> -#include "X11/Xutil.h" +#include <X11/Xatom.h> +#include <X11/Xutil.h> +#include <X11/extensions/Xinerama.h> +#include <X11/extensions/shape.h> -#include "X11/Xatom.h" -#include "X11/extensions/Xinerama.h" // ICCCM #define WM_NormalState 1L // window normal state #define WM_IconicState 3L // window minimized @@ -69,8 +61,6 @@ #define _NET_WM_STATE_ADD 1L // add/set property #define _NET_WM_STATE_TOGGLE 2L // toggle property -#include "main/main.h" - #include <dlfcn.h> #include <fcntl.h> #include <sys/stat.h> @@ -82,14 +72,9 @@ #undef KEY_TAB #endif -#include <X11/Xatom.h> - #undef CursorShape - #include <X11/XKBlib.h> -#include "core/project_settings.h" - // 2.2 is the first release with multitouch #define XINPUT_CLIENT_VERSION_MAJOR 2 #define XINPUT_CLIENT_VERSION_MINOR 2 @@ -100,9 +85,25 @@ #define VALUATOR_TILTX 3 #define VALUATOR_TILTY 4 +//#define DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED +#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED +#define DEBUG_LOG_X11(...) printf(__VA_ARGS__) +#else +#define DEBUG_LOG_X11(...) +#endif + 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: @@ -190,7 +191,7 @@ void DisplayServerX11::alert(const String &p_alert, const String &p_title) { } if (program.length()) { - OS::get_singleton()->execute(program, args, true); + OS::get_singleton()->execute(program, args); } else { print_line(p_alert); } @@ -331,23 +332,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; } } @@ -417,17 +414,24 @@ void DisplayServerX11::mouse_warp_to_position(const Point2i &p_to) { if (mouse_mode == MOUSE_MODE_CAPTURED) { last_mouse_pos = p_to; } else { - /*XWindowAttributes xwa; - XGetWindowAttributes(x11_display, x11_window, &xwa); - printf("%d %d\n", xwa.x, xwa.y); needed? */ - XWarpPointer(x11_display, None, windows[MAIN_WINDOW_ID].x11_window, 0, 0, 0, 0, (int)p_to.x, (int)p_to.y); } } Point2i DisplayServerX11::mouse_get_position() const { - return last_mouse_pos; + int root_x, root_y; + int win_x, win_y; + unsigned int mask_return; + Window window_returned; + + Bool result = XQueryPointer(x11_display, RootWindow(x11_display, DefaultScreen(x11_display)), &window_returned, + &window_returned, &root_x, &root_y, &win_x, &win_y, + &mask_return); + if (result == True) { + return Point2i(root_x, root_y); + } + return Point2i(); } Point2i DisplayServerX11::mouse_get_absolute_position() const { @@ -453,60 +457,156 @@ int DisplayServerX11::mouse_get_button_state() const { 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) { +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) { + return internal_clipboard; + } - if (Sown != None) { + if (selection_owner != None) { + // Block events polling while processing selection events. + MutexLock mutex_lock(events_mutex); + + Atom selection = XA_PRIMARY; XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime); + XFlush(x11_display); - 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); } @@ -516,14 +616,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; } @@ -532,15 +632,69 @@ 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; } +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_ @@ -691,6 +845,14 @@ DisplayServer::WindowID DisplayServerX11::create_sub_window(WindowMode p_mode, u return id; } +void DisplayServerX11::show_window(WindowID p_id) { + _THREAD_SAFE_METHOD_ + + WindowData &wd = windows[p_id]; + + XMapWindow(x11_display, wd.x11_window); +} + void DisplayServerX11::delete_sub_window(WindowID p_id) { _THREAD_SAFE_METHOD_ @@ -699,6 +861,8 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { WindowData &wd = windows[p_id]; + DEBUG_LOG_X11("delete_sub_window: %lu (%u) \n", wd.x11_window, p_id); + while (wd.transient_children.size()) { window_set_transient(wd.transient_children.front()->get(), INVALID_WINDOW_ID); } @@ -716,6 +880,7 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { XDestroyWindow(x11_display, wd.x11_window); if (wd.xic) { XDestroyIC(wd.xic); + wd.xic = nullptr; } windows.erase(p_id); @@ -735,7 +900,31 @@ ObjectID DisplayServerX11::window_get_attached_instance_id(WindowID p_window) co } DisplayServerX11::WindowID DisplayServerX11::get_window_at_screen_position(const Point2i &p_position) const { - return INVALID_WINDOW_ID; + 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(); + + // Discard windows with no focus. + if (wd.focus_order == 0) { + continue; + } + + // Find topmost window which contains the given position. + 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. + if ((parent_window != wd.transient_parent) || (wd.focus_order > focus_order)) { + found_window = window_id; + parent_window = wd.transient_parent; + focus_order = wd.focus_order; + } + } + } + + return found_window; } void DisplayServerX11::window_set_title(const String &p_title, WindowID p_window) { @@ -748,7 +937,41 @@ 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) { + _THREAD_SAFE_METHOD_ + + ERR_FAIL_COND(!windows.has(p_window)); + const WindowData &wd = windows[p_window]; + + int event_base, error_base; + const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base); + if (ext_okay) { + Region region; + if (p_region.size() == 0) { + region = XCreateRegion(); + XRectangle rect; + rect.x = 0; + rect.y = 0; + rect.width = window_get_real_size(p_window).x; + rect.height = window_get_real_size(p_window).y; + XUnionRectWithRegion(&rect, region, region); + } else { + XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size()); + for (int i = 0; i < p_region.size(); i++) { + points[i].x = p_region[i].x; + points[i].y = p_region[i].y; + } + region = XPolygonRegion(points, p_region.size(), EvenOddRule); + memfree(points); + } + XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); + } } void DisplayServerX11::window_set_rect_changed_callback(const Callable &p_callable, WindowID p_window) { @@ -844,24 +1067,34 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent ERR_FAIL_COND(!windows.has(p_window)); WindowData &wd_window = windows[p_window]; - ERR_FAIL_COND(wd_window.transient_parent == p_parent); + WindowID prev_parent = wd_window.transient_parent; + ERR_FAIL_COND(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 - ERR_FAIL_COND(wd_window.transient_parent == INVALID_WINDOW_ID); - ERR_FAIL_COND(!windows.has(wd_window.transient_parent)); + ERR_FAIL_COND(prev_parent == INVALID_WINDOW_ID); + ERR_FAIL_COND(!windows.has(prev_parent)); - WindowData &wd_parent = windows[wd_window.transient_parent]; + WindowData &wd_parent = windows[prev_parent]; wd_window.transient_parent = INVALID_WINDOW_ID; wd_parent.transient_children.erase(p_window); XSetTransientForHint(x11_display, wd_window.x11_window, None); + + // Set focus to parent sub window to avoid losing all focus with nested menus. + // 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_parent.no_focus) { + XSetInputFocus(x11_display, wd_parent.x11_window, RevertToPointerRoot, CurrentTime); + } + } } else { ERR_FAIL_COND(!windows.has(p_parent)); - ERR_FAIL_COND_MSG(wd_window.transient_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); + ERR_FAIL_COND_MSG(prev_parent != INVALID_WINDOW_ID, "Window already has a transient parent"); WindowData &wd_parent = windows[p_parent]; wd_window.transient_parent = p_parent; @@ -871,6 +1104,46 @@ void DisplayServerX11::window_set_transient(WindowID p_window, WindowID p_parent } } +// Helper method. Assumes that the window id has already been checked and exists. +void DisplayServerX11::_update_size_hints(WindowID p_window) { + WindowData &wd = windows[p_window]; + WindowMode window_mode = window_get_mode(p_window); + XSizeHints *xsh = XAllocSizeHints(); + + // Always set the position and size hints - they should be synchronized with the actual values after the window is mapped anyway + xsh->flags |= PPosition | PSize; + xsh->x = wd.position.x; + xsh->y = wd.position.y; + xsh->width = wd.size.width; + xsh->height = wd.size.height; + + if (window_mode == WINDOW_MODE_FULLSCREEN) { + // Do not set any other hints to prevent the window manager from ignoring the fullscreen flags + } else if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { + // If resizing is disabled, use the forced size + xsh->flags |= PMinSize | PMaxSize; + xsh->min_width = wd.size.x; + xsh->max_width = wd.size.x; + xsh->min_height = wd.size.y; + xsh->max_height = wd.size.y; + } else { + // Otherwise, just respect min_size and max_size + if (wd.min_size != Size2i()) { + xsh->flags |= PMinSize; + xsh->min_width = wd.min_size.x; + xsh->min_height = wd.min_size.y; + } + if (wd.max_size != Size2i()) { + xsh->flags |= PMaxSize; + xsh->max_width = wd.max_size.x; + xsh->max_height = wd.max_size.y; + } + } + + XSetWMNormalHints(x11_display, wd.x11_window, xsh); + XFree(xsh); +} + Point2i DisplayServerX11::window_get_position(WindowID p_window) const { _THREAD_SAFE_METHOD_ @@ -924,25 +1197,8 @@ void DisplayServerX11::window_set_max_size(const Size2i p_size, WindowID p_windo } wd.max_size = p_size; - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - - XFlush(x11_display); - } + _update_size_hints(p_window); + XFlush(x11_display); } Size2i DisplayServerX11::window_get_max_size(WindowID p_window) const { @@ -966,25 +1222,8 @@ void DisplayServerX11::window_set_min_size(const Size2i p_size, WindowID p_windo } wd.min_size = p_size; - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - - XFlush(x11_display); - } + _update_size_hints(p_window); + XFlush(x11_display); } Size2i DisplayServerX11::window_get_min_size(WindowID p_window) const { @@ -1017,37 +1256,15 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { int old_w = xwa.width; int old_h = xwa.height; - // If window resizable is disabled we need to update the attributes first - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (!window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + // Update our videomode width and height + wd.size = size; + + // Update the size hints first to make sure the window size can be set + _update_size_hints(p_window); // Resize the window XResizeWindow(x11_display, wd.x11_window, size.x, size.y); - // Update our videomode width and height - wd.size = size; - for (int timeout = 0; timeout < 50; ++timeout) { XSync(x11_display, False); XGetWindowAttributes(x11_display, wd.x11_window, &xwa); @@ -1098,18 +1315,23 @@ Size2i DisplayServerX11::window_get_real_size(WindowID p_window) const { return Size2i(w, h); } -bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { - _THREAD_SAFE_METHOD_ - +// Just a helper to reduce code duplication in `window_is_maximize_allowed` +// and `_set_wm_maximized`. +bool DisplayServerX11::_window_maximize_check(WindowID p_window, const char *p_atom_name) const { ERR_FAIL_COND_V(!windows.has(p_window), false); const WindowData &wd = windows[p_window]; - Atom property = XInternAtom(x11_display, "_NET_WM_ALLOWED_ACTIONS", False); + Atom property = XInternAtom(x11_display, p_atom_name, False); Atom type; int format; unsigned long len; unsigned long remaining; unsigned char *data = nullptr; + bool retval = false; + + if (property == None) { + return false; + } int result = XGetWindowProperty( x11_display, @@ -1141,13 +1363,20 @@ bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { } if (found_wm_act_max_horz || found_wm_act_max_vert) { - return true; + retval = true; + break; } } - XFree(atoms); + + XFree(data); } - return false; + return retval; +} + +bool DisplayServerX11::window_is_maximize_allowed(WindowID p_window) const { + _THREAD_SAFE_METHOD_ + return _window_maximize_check(p_window, "_NET_WM_ALLOWED_ACTIONS"); } void DisplayServerX11::_set_wm_maximized(WindowID p_window, bool p_enabled) { @@ -1192,17 +1421,14 @@ 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 && window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { + if (p_enabled) { // Set the window as resizable to prevent window managers to ignore the fullscreen state flag. - XSizeHints *xsh; - - xsh = XAllocSizeHints(); - xsh->flags = 0L; - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + _update_size_hints(p_window); } // Using EWMH -- Extended Window Manager Hints @@ -1224,36 +1450,15 @@ 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); if (!p_enabled) { // Reset the non-resizable flags if we un-set these before. - Size2i size = window_get_size(p_window); - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (window_get_flag(WINDOW_FLAG_RESIZE_DISABLED, p_window)) { - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); + _update_size_hints(p_window); // put back or remove decorations according to the last set borderless state Hints hints; @@ -1261,7 +1466,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); + } } } @@ -1311,13 +1518,13 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { } break; case WINDOW_MODE_FULLSCREEN: { //Remove full-screen + wd.fullscreen = false; + _set_wm_fullscreen(p_window, false); //un-maximize required for always on top bool on_top = window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window); - wd.fullscreen = false; - window_set_position(wd.last_position_before_fs, p_window); if (on_top) { @@ -1363,15 +1570,16 @@ void DisplayServerX11::window_set_mode(WindowMode p_mode, WindowID p_window) { } break; case WINDOW_MODE_FULLSCREEN: { wd.last_position_before_fs = wd.position; + if (window_get_flag(WINDOW_FLAG_ALWAYS_ON_TOP, p_window)) { _set_wm_maximized(p_window, true); } - _set_wm_fullscreen(p_window, true); + wd.fullscreen = true; + _set_wm_fullscreen(p_window, true); } break; case WINDOW_MODE_MAXIMIZED: { _set_wm_maximized(p_window, true); - } break; } } @@ -1385,62 +1593,20 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c if (wd.fullscreen) { //if fullscreen, it's not in another mode return WINDOW_MODE_FULLSCREEN; } - { //test maximized - // Using EWMH -- Extended Window Manager Hints - Atom property = XInternAtom(x11_display, "_NET_WM_STATE", False); - Atom type; - int format; - unsigned long len; - unsigned long remaining; - unsigned char *data = nullptr; - bool retval = false; - int result = XGetWindowProperty( - x11_display, - wd.x11_window, - property, - 0, - 1024, - False, - XA_ATOM, - &type, - &format, - &len, - &remaining, - &data); - - if (result == Success && data) { - Atom *atoms = (Atom *)data; - Atom wm_max_horz = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); - Atom wm_max_vert = XInternAtom(x11_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); - bool found_wm_max_horz = false; - bool found_wm_max_vert = false; - - for (uint64_t i = 0; i < len; i++) { - if (atoms[i] == wm_max_horz) { - found_wm_max_horz = true; - } - if (atoms[i] == wm_max_vert) { - found_wm_max_vert = true; - } - - if (found_wm_max_horz && found_wm_max_vert) { - retval = true; - break; - } - } - - XFree(data); - } - - if (retval) { - return WINDOW_MODE_MAXIMIZED; - } + // Test maximized. + // Using EWMH -- Extended Window Manager Hints + if (_window_maximize_check(p_window, "_NET_WM_STATE")) { + return WINDOW_MODE_MAXIMIZED; } - { // test minimzed + { // 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; @@ -1471,7 +1637,7 @@ DisplayServer::WindowMode DisplayServerX11::window_get_mode(WindowID p_window) c } } - // all other discarded, return windowed. + // All other discarded, return windowed. return WINDOW_MODE_WINDOWED; } @@ -1484,37 +1650,11 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo switch (p_flag) { case WINDOW_FLAG_RESIZE_DISABLED: { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - if (p_enabled) { - Size2i size = window_get_size(p_window); - - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = size.x; - xsh->max_width = size.x; - xsh->min_height = size.y; - xsh->max_height = size.y; - } else { - xsh->flags = 0L; - if (wd.min_size != Size2i()) { - xsh->flags |= PMinSize; - xsh->min_width = wd.min_size.x; - xsh->min_height = wd.min_size.y; - } - if (wd.max_size != Size2i()) { - xsh->flags |= PMaxSize; - xsh->max_width = wd.max_size.x; - xsh->max_height = wd.max_size.y; - } - } - - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - wd.resize_disabled = p_enabled; - XFlush(x11_display); + _update_size_hints(p_window); + XFlush(x11_display); } break; case WINDOW_FLAG_BORDERLESS: { Hints hints; @@ -1522,7 +1662,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); @@ -1682,10 +1824,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); } } @@ -1706,7 +1854,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); } @@ -1846,62 +2001,132 @@ void DisplayServerX11::cursor_set_custom_image(const RES &p_cursor, CursorShape } } -DisplayServerX11::LatinKeyboardVariant DisplayServerX11::get_latin_keyboard_variant() const { - _THREAD_SAFE_METHOD_ - - XkbDescRec *xkbdesc = XkbAllocKeyboard(); - ERR_FAIL_COND_V(!xkbdesc, LATIN_KEYBOARD_QWERTY); +int DisplayServerX11::keyboard_get_layout_count() const { + int _group_count = 0; + XkbDescRec *kbd = XkbAllocKeyboard(); + if (kbd) { + kbd->dpy = x11_display; + XkbGetControls(x11_display, XkbAllControlsMask, kbd); + XkbGetNames(x11_display, XkbSymbolsNameMask, kbd); + + const Atom *groups = kbd->names->groups; + if (kbd->ctrls != NULL) { + _group_count = kbd->ctrls->num_groups; + } else { + while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { + _group_count++; + } + } + XkbFreeKeyboard(kbd, 0, true); + } + return _group_count; +} - XkbGetNames(x11_display, XkbSymbolsNameMask, xkbdesc); - ERR_FAIL_COND_V(!xkbdesc->names, LATIN_KEYBOARD_QWERTY); - ERR_FAIL_COND_V(!xkbdesc->names->symbols, LATIN_KEYBOARD_QWERTY); +int DisplayServerX11::keyboard_get_current_layout() const { + XkbStateRec state; + XkbGetState(x11_display, XkbUseCoreKbd, &state); + return state.group; +} - char *layout = XGetAtomName(x11_display, xkbdesc->names->symbols); - ERR_FAIL_COND_V(!layout, LATIN_KEYBOARD_QWERTY); +void DisplayServerX11::keyboard_set_current_layout(int p_index) { + ERR_FAIL_INDEX(p_index, keyboard_get_layout_count()); + XkbLockGroup(x11_display, XkbUseCoreKbd, p_index); +} - Vector<String> info = String(layout).split("+"); - ERR_FAIL_INDEX_V(1, info.size(), LATIN_KEYBOARD_QWERTY); +String DisplayServerX11::keyboard_get_layout_language(int p_index) const { + String ret; + XkbDescRec *kbd = XkbAllocKeyboard(); + if (kbd) { + kbd->dpy = x11_display; + XkbGetControls(x11_display, XkbAllControlsMask, kbd); + XkbGetNames(x11_display, XkbSymbolsNameMask, kbd); + XkbGetNames(x11_display, XkbGroupNamesMask, kbd); + + int _group_count = 0; + const Atom *groups = kbd->names->groups; + if (kbd->ctrls != NULL) { + _group_count = kbd->ctrls->num_groups; + } else { + while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { + _group_count++; + } + } - if (info[1].find("colemak") != -1) { - return LATIN_KEYBOARD_COLEMAK; - } else if (info[1].find("qwertz") != -1) { - return LATIN_KEYBOARD_QWERTZ; - } else if (info[1].find("azerty") != -1) { - return LATIN_KEYBOARD_AZERTY; - } else if (info[1].find("qzerty") != -1) { - return LATIN_KEYBOARD_QZERTY; - } else if (info[1].find("dvorak") != -1) { - return LATIN_KEYBOARD_DVORAK; - } else if (info[1].find("neo") != -1) { - return LATIN_KEYBOARD_NEO; + Atom names = kbd->names->symbols; + if (names != None) { + char *name = XGetAtomName(x11_display, names); + Vector<String> info = String(name).split("+"); + if (p_index >= 0 && p_index < _group_count) { + if (p_index + 1 < info.size()) { + ret = info[p_index + 1]; // Skip "pc" at the start and "inet"/"group" at the end of symbols. + } else { + ret = "en"; // No symbol for layout fallback to "en". + } + } else { + ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ")."); + } + XFree(name); + } + XkbFreeKeyboard(kbd, 0, true); } + return ret.substr(0, 2); +} + +String DisplayServerX11::keyboard_get_layout_name(int p_index) const { + String ret; + XkbDescRec *kbd = XkbAllocKeyboard(); + if (kbd) { + kbd->dpy = x11_display; + XkbGetControls(x11_display, XkbAllControlsMask, kbd); + XkbGetNames(x11_display, XkbSymbolsNameMask, kbd); + XkbGetNames(x11_display, XkbGroupNamesMask, kbd); + + int _group_count = 0; + const Atom *groups = kbd->names->groups; + if (kbd->ctrls != NULL) { + _group_count = kbd->ctrls->num_groups; + } else { + while (_group_count < XkbNumKbdGroups && groups[_group_count] != None) { + _group_count++; + } + } - return LATIN_KEYBOARD_QWERTY; + if (p_index >= 0 && p_index < _group_count) { + char *full_name = XGetAtomName(x11_display, groups[p_index]); + ret.parse_utf8(full_name); + XFree(full_name); + } else { + ERR_PRINT("Index " + itos(p_index) + "is out of bounds (" + itos(_group_count) + ")."); + } + XkbFreeKeyboard(kbd, 0, true); + } + return ret; } 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 }; @@ -1957,7 +2182,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; @@ -2094,7 +2319,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. @@ -2128,17 +2353,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 @@ -2153,9 +2377,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 } } @@ -2210,6 +2434,118 @@ void DisplayServerX11::_handle_key_event(WindowID p_window, XKeyEvent *p_event, Input::get_singleton()->accumulate_input_event(k); } +Atom DisplayServerX11::_process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property) const { + if (p_target == XInternAtom(x11_display, "TARGETS", 0)) { + // Request to list all supported targets. + Atom data[9]; + data[0] = XInternAtom(x11_display, "TARGETS", 0); + data[1] = XInternAtom(x11_display, "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 = 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); + } + + XChangeProperty(x11_display, + p_event->requestor, + p_event->property, + atom_pair, + 32, + PropModeReplace, + (unsigned char *)targets, + len); + + respond.xselection.property = p_event->property; + } + XFree(data); + } + } else { + // Request for target conversion. + respond.xselection.property = _process_selection_request_target(p_event->target, p_event->requestor, p_event->property); + } + + respond.xselection.type = SelectionNotify; + 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, ::XPointer call_data) { WARN_PRINT("Input method stopped"); @@ -2322,9 +2658,110 @@ 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, NULL, NULL, &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); + + // 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; + } + + polled_events.push_back(ev); + } + } + } +} + void DisplayServerX11::process_events() { _THREAD_SAFE_METHOD_ +#ifdef DISPLAY_SERVER_X11_DEBUG_LOGS_ENABLED + static int frame = 0; + ++frame; +#endif + + 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) { + focus_found = true; + break; + } + } + + if (!focus_found) { + uint64_t delta = OS::get_singleton()->get_ticks_msec() - time_since_no_focus; + + if (delta > 250) { + //X11 can go between windows and have no focus for a while, when creating them or something else. Use this as safety to avoid unnecessary focus in/outs. + if (OS::get_singleton()->get_main_loop()) { + DEBUG_LOG_X11("All focus lost, triggering NOTIFICATION_APPLICATION_FOCUS_OUT\n"); + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT); + } + app_focused = false; + } + } else { + time_since_no_focus = OS::get_singleton()->get_ticks_msec(); + } + } + do_mouse_warp = false; // Is the current mouse mode one where it needs to be grabbed. @@ -2334,9 +2771,16 @@ void DisplayServerX11::process_events() { 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(); + } + + for (uint32_t event_index = 0; event_index < events.size(); ++event_index) { + XEvent &event = events[event_index]; WindowID window_id = MAIN_WINDOW_ID; @@ -2348,10 +2792,6 @@ void DisplayServerX11::process_events() { } } - if (XFilterEvent(&event, None)) { - continue; - } - if (XGetEventData(x11_display, &event.xcookie)) { if (event.xcookie.type == GenericEvent && event.xcookie.extension == xi.opcode) { XIDeviceEvent *event_data = (XIDeviceEvent *)event.xcookie.data; @@ -2514,34 +2954,74 @@ void DisplayServerX11::process_events() { XFreeEventData(x11_display, &event.xcookie); switch (event.type) { - case Expose: + case MapNotify: { + DEBUG_LOG_X11("[%u] MapNotify window=%lu (%u) \n", frame, event.xmap.window, window_id); + + const WindowData &wd = windows[window_id]; + + // Set focus when menu window is started. + // RevertToPointerRoot is used to make sure we don't lose all focus in case + // a subwindow and its parent are both destroyed. + if (wd.menu_type && !wd.no_focus) { + XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); + } + } break; + + case Expose: { + DEBUG_LOG_X11("[%u] Expose window=%lu (%u), count='%u' \n", frame, event.xexpose.window, window_id, event.xexpose.count); + Main::force_redraw(); - break; + } break; - case NoExpose: - minimized = true; - break; + case NoExpose: { + DEBUG_LOG_X11("[%u] NoExpose drawable=%lu (%u) \n", frame, event.xnoexpose.drawable, window_id); + + windows[window_id].minimized = true; + } break; case VisibilityNotify: { + DEBUG_LOG_X11("[%u] VisibilityNotify window=%lu (%u), state=%u \n", frame, event.xvisibility.window, window_id, event.xvisibility.state); + XVisibilityEvent *visibility = (XVisibilityEvent *)&event; - minimized = (visibility->state == VisibilityFullyObscured); + windows[window_id].minimized = (visibility->state == VisibilityFullyObscured); } break; + case LeaveNotify: { + DEBUG_LOG_X11("[%u] LeaveNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode); + if (!mouse_mode_grab) { _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_EXIT); } } break; + case EnterNotify: { + DEBUG_LOG_X11("[%u] EnterNotify window=%lu (%u), mode='%u' \n", frame, event.xcrossing.window, window_id, event.xcrossing.mode); + if (!mouse_mode_grab) { _send_window_event(windows[window_id], WINDOW_EVENT_MOUSE_ENTER); } } break; - case FocusIn: - minimized = false; - window_has_focus = true; - _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_IN); - window_focused = true; + + case FocusIn: { + DEBUG_LOG_X11("[%u] FocusIn window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode); + + WindowData &wd = windows[window_id]; + + 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; + + _send_window_event(wd, WINDOW_EVENT_FOCUS_IN); if (mouse_mode_grab) { // Show and update the cursor if confined and the window regained focus. @@ -2565,16 +3045,31 @@ void DisplayServerX11::process_events() { XIGrabDevice(x11_display, xi.touch_devices[i], x11_window, CurrentTime, None, XIGrabModeAsync, XIGrabModeAsync, False, &xi.touch_event_mask); }*/ #endif - if (windows[window_id].xic) { - XSetICFocus(windows[window_id].xic); + + if (!app_focused) { + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN); + } + app_focused = true; + } + } break; + + case FocusOut: { + DEBUG_LOG_X11("[%u] FocusOut window=%lu (%u), mode='%u' \n", frame, event.xfocus.window, window_id, event.xfocus.mode); + + WindowData &wd = windows[window_id]; + + 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); } - break; - case FocusOut: - window_has_focus = false; Input::get_singleton()->release_pressed_events(); - _send_window_event(windows[window_id], WINDOW_EVENT_FOCUS_OUT); - window_focused = false; + _send_window_event(wd, WINDOW_EVENT_FOCUS_OUT); if (mouse_mode_grab) { for (Map<WindowID, WindowData>::Element *E = windows.front(); E; E = E->next()) { @@ -2603,14 +3098,23 @@ void DisplayServerX11::process_events() { } xi.state.clear(); #endif - if (windows[window_id].xic) { - XSetICFocus(windows[window_id].xic); + } break; + + case ConfigureNotify: { + DEBUG_LOG_X11("[%u] ConfigureNotify window=%lu (%u), event=%lu, above=%lu, override_redirect=%u \n", frame, event.xconfigure.window, window_id, event.xconfigure.event, event.xconfigure.above, event.xconfigure.override_redirect); + + const WindowData &wd = windows[window_id]; + + // Set focus when menu window is re-used. + // RevertToPointerRoot is used to make sure we don't lose all focus in case + // a subwindow and its parent are both destroyed. + if (wd.menu_type && !wd.no_focus) { + XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); } - break; - case ConfigureNotify: _window_changed(&event); - break; + } break; + case ButtonPress: case ButtonRelease: { /* exit in case of a mouse button press */ @@ -2637,7 +3141,18 @@ void DisplayServerX11::process_events() { mb->set_pressed((event.type == ButtonPress)); + const WindowData &wd = windows[window_id]; + if (event.type == ButtonPress) { + DEBUG_LOG_X11("[%u] ButtonPress window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index()); + + // Ensure window focus on click. + // RevertToPointerRoot is used to make sure we don't lose all focus in case + // a subwindow and its parent are both destroyed. + if (!wd.no_focus) { + XSetInputFocus(x11_display, wd.x11_window, RevertToPointerRoot, CurrentTime); + } + uint64_t diff = OS::get_singleton()->get_ticks_usec() / 1000 - last_click_ms; if (mb->get_button_index() == last_click_button_index) { @@ -2656,6 +3171,33 @@ void DisplayServerX11::process_events() { last_click_ms += diff; last_click_pos = Point2i(event.xbutton.x, event.xbutton.y); } + } else { + DEBUG_LOG_X11("[%u] ButtonRelease window=%lu (%u), button_index=%u \n", frame, event.xbutton.window, window_id, mb->get_button_index()); + + if (!wd.focused) { + // 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(); + WindowID window_id_other = E->key(); + if (wd_other.focused) { + if (window_id_other != window_id) { + int x, y; + Window child; + XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xbutton.x, event.xbutton.y, &x, &y, &child); + + 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); + } + break; + } + } + } } Input::get_singleton()->accumulate_input_event(mb); @@ -2673,11 +3215,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; } @@ -2705,6 +3247,9 @@ void DisplayServerX11::process_events() { break; } + const WindowData &wd = windows[window_id]; + bool focused = wd.focused; + if (mouse_mode == MOUSE_MODE_CAPTURED) { if (xi.relative_motion.x == 0 && xi.relative_motion.y == 0) { break; @@ -2713,7 +3258,7 @@ void DisplayServerX11::process_events() { Point2i new_center = pos; pos = last_mouse_pos + xi.relative_motion; center = new_center; - do_mouse_warp = window_has_focus; // warp the cursor if we're focused in + do_mouse_warp = focused; // warp the cursor if we're focused in } if (!last_mouse_pos_valid) { @@ -2755,14 +3300,11 @@ void DisplayServerX11::process_events() { } mm->set_tilt(xi.tilt); - // Make the absolute position integral so it doesn't look _too_ weird :) - Point2i posi(pos); - _get_key_modifier_state(event.xmotion.state, mm); mm->set_button_mask(mouse_get_button_state()); - mm->set_position(posi); - mm->set_global_position(posi); - Input::get_singleton()->set_mouse_position(posi); + mm->set_position(pos); + mm->set_global_position(pos); + Input::get_singleton()->set_mouse_position(pos); mm->set_speed(Input::get_singleton()->get_last_mouse_speed()); mm->set_relative(rel); @@ -2773,8 +3315,32 @@ void DisplayServerX11::process_events() { // Don't propagate the motion event unless we have focus // this is so that the relative motion doesn't get messed up // after we regain focus. - if (window_has_focus || !mouse_mode_grab) { + if (focused) { Input::get_singleton()->accumulate_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(); + if (wd_other.focused) { + int x, y; + Window child; + XTranslateCoordinates(x11_display, wd.x11_window, wd_other.x11_window, event.xmotion.x, event.xmotion.y, &x, &y, &child); + + Point2i pos_focused(x, y); + + 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); + + break; + } + } } } break; @@ -2784,67 +3350,7 @@ void DisplayServerX11::process_events() { // 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, (XKeyEvent *)&event, events, event_index); } break; case SelectionNotify: @@ -2854,7 +3360,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()) { @@ -3095,7 +3601,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; @@ -3123,7 +3631,13 @@ Vector<String> DisplayServerX11::get_rendering_drivers_func() { } DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, WindowMode p_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { - return memnew(DisplayServerX11(p_rendering_driver, p_mode, p_flags, p_resolution, r_error)); + DisplayServer *ds = memnew(DisplayServerX11(p_rendering_driver, p_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.", + "Unable to initialize Video driver"); + } + return ds; } DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, uint32_t p_flags, const Rect2i &p_rect) { @@ -3145,19 +3659,46 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u unsigned long valuemask = CWBorderPixel | CWColormap | CWEventMask; - WindowID id; + WindowID id = window_id_counter++; + WindowData &wd = windows[id]; + + if ((id != MAIN_WINDOW_ID) && (p_flags & WINDOW_FLAG_BORDERLESS_BIT)) { + wd.menu_type = true; + } + + if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { + wd.menu_type = true; + wd.no_focus = true; + } + + // Setup for menu subwindows: + // - override_redirect forces the WM not to interfere with the window, to avoid delays due to + // handling decorations and placement. + // On the other hand, focus changes need to be handled manually when this is set. + // - save_under is a hint for the WM to keep the content of windows behind to avoid repaint. + if (wd.menu_type) { + windowAttributes.override_redirect = True; + windowAttributes.save_under = True; + valuemask |= CWOverrideRedirect | CWSaveUnder; + } + { - WindowData wd; wd.x11_window = XCreateWindow(x11_display, RootWindow(x11_display, visualInfo->screen), p_rect.position.x, p_rect.position.y, p_rect.size.width > 0 ? p_rect.size.width : 1, p_rect.size.height > 0 ? p_rect.size.height : 1, 0, visualInfo->depth, InputOutput, visualInfo->visual, valuemask, &windowAttributes); - XMapWindow(x11_display, wd.x11_window); + // Enable receiving notification when the window is initialized (MapNotify) + // so the focus can be set at the right time. + if (wd.menu_type && !wd.no_focus) { + XSelectInput(x11_display, wd.x11_window, StructureNotifyMask); + } //associate PID // make PID known to X11 { 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; @@ -3205,9 +3746,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"); @@ -3226,86 +3773,34 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u _update_context(wd); - id = window_id_counter++; - - windows[id] = wd; - - { - if (p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT) { - XSizeHints *xsh; - xsh = XAllocSizeHints(); - - xsh->flags = PMinSize | PMaxSize; - xsh->min_width = p_rect.size.width; - xsh->max_width = p_rect.size.width; - xsh->min_height = p_rect.size.height; - xsh->max_height = p_rect.size.height; - - XSetWMNormalHints(x11_display, wd.x11_window, xsh); - XFree(xsh); - } - - bool make_utility = false; - - if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { - Hints hints; - Atom property; - hints.flags = 2; - hints.decorations = 0; - property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + if (p_flags & WINDOW_FLAG_BORDERLESS_BIT) { + Hints hints; + Atom property; + hints.flags = 2; + hints.decorations = 0; + property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); + if (property != None) { XChangeProperty(x11_display, wd.x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); - - make_utility = true; - } - if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) { - make_utility = true; } + } - if (make_utility) { - //this one seems to disable the fade animations for regular windows - //but has the drawback that will not get focus by default, so - //we need fo force it, unless no focus requested - - Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_UTILITY", False); - Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - + 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); + 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); - if (!(p_flags & WINDOW_FLAG_NO_FOCUS_BIT)) { - //but as utility appears unfocused, it needs to be forcefuly focused, unless no focus requested - XEvent xev; - Atom net_active_window = XInternAtom(x11_display, "_NET_ACTIVE_WINDOW", False); - - memset(&xev, 0, sizeof(xev)); - xev.type = ClientMessage; - xev.xclient.window = wd.x11_window; - xev.xclient.message_type = net_active_window; - xev.xclient.format = 32; - xev.xclient.data.l[0] = 1; - xev.xclient.data.l[1] = CurrentTime; - - XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev); - } - } else { - Atom type_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE_NORMAL", False); - Atom wt_atom = XInternAtom(x11_display, "_NET_WM_WINDOW_TYPE", False); - + if (wt_atom != None && type_atom != None) { XChangeProperty(x11_display, wd.x11_window, wt_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&type_atom, 1); } } - if (id != MAIN_WINDOW_ID) { - XSizeHints my_hints = XSizeHints(); - - my_hints.flags = PPosition | PSize; /* I want to specify position and size */ - my_hints.x = p_rect.position.x; /* The origin and size coords I want */ - my_hints.y = p_rect.position.y; - my_hints.width = p_rect.size.width; - my_hints.height = p_rect.size.height; - - XSetNormalHints(x11_display, wd.x11_window, &my_hints); - XMoveWindow(x11_display, wd.x11_window, p_rect.position.x, p_rect.position.y); - } + _update_size_hints(id); #if defined(VULKAN_ENABLED) if (context_vulkan) { @@ -3323,8 +3818,6 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u XFree(visualInfo); } - WindowData &wd = windows[id]; - window_set_mode(p_mode, id); //sync size @@ -3346,6 +3839,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, u if (cursors[current_cursor] != None) { XDefineCursor(x11_display, wd.x11_window, cursors[current_cursor]); } + return id; } @@ -3417,7 +3911,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode xrandr_handle = dlopen("libXrandr.so.2", RTLD_LAZY); if (!xrandr_handle) { err = dlerror(); - fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err); + // For some arcane reason, NetBSD now ships libXrandr.so.3 while the rest of the world has libXrandr.so.2... + // In case this happens for other X11 platforms in the future, let's give it a try too before failing. + xrandr_handle = dlopen("libXrandr.so.3", RTLD_LAZY); + if (!xrandr_handle) { + fprintf(stderr, "could not load libXrandr.so.2, Error: %s\n", err); + } } else { XRRQueryVersion(x11_display, &xrandr_major, &xrandr_minor); if (((xrandr_major << 8) | xrandr_minor) >= 0x0105) { @@ -3580,11 +4079,16 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode (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)); + 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); } } + show_window(main_window); //create RenderingDevice if used #if defined(VULKAN_ENABLED) @@ -3593,12 +4097,12 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode rendering_device_vulkan = memnew(RenderingDeviceVulkan); rendering_device_vulkan->initialize(context_vulkan); - RasterizerRD::make_current(); + RendererCompositorRD::make_current(); } #endif /* - rendering_server = memnew(RenderingServerRaster); + rendering_server = memnew(RenderingServerDefault); if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) { rendering_server = memnew(RenderingServerWrapMT(rendering_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD)); } @@ -3750,8 +4254,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode requested = None; - window_has_focus = true; // Set focus to true at init - /*if (p_desired.layered) { set_window_per_pixel_transparency_enabled(true); }*/ @@ -3764,12 +4266,22 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode } } + events_thread.start(_poll_events_thread, this); + _update_real_mouse_position(windows[MAIN_WINDOW_ID]); 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()) { #ifdef VULKAN_ENABLED @@ -3778,11 +4290,13 @@ DisplayServerX11::~DisplayServerX11() { } #endif - if (E->get().xic) { - XDestroyIC(E->get().xic); + WindowData &wd = E->get(); + 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 diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index b5ea71f72a..10686d8424 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 */ @@ -36,14 +36,14 @@ #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) @@ -61,27 +61,18 @@ #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 @@ -133,6 +124,9 @@ class DisplayServerX11 : public DisplayServer { ObjectID instance_id; + bool menu_type = false; + bool no_focus = false; + //better to guess on the fly, given WM can change it //WindowMode mode; bool fullscreen = false; //OS can't exit from this mode @@ -140,6 +134,10 @@ class DisplayServerX11 : public DisplayServer { bool borderless = false; bool resize_disabled = false; Vector2i last_position_before_fs; + bool focused = false; + bool minimized = false; + + unsigned int focus_order = 0; }; Map<WindowID, WindowData> windows; @@ -165,6 +163,8 @@ class DisplayServerX11 : public DisplayServer { uint64_t last_click_ms; int last_click_button_index; uint32_t last_button_state; + bool app_focused = false; + uint64_t time_since_no_focus = 0; struct { int opcode; @@ -194,10 +194,17 @@ class DisplayServerX11 : public DisplayServer { 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) const; + void _handle_selection_request_event(XSelectionRequestEvent *p_event) const; - bool minimized; - bool window_has_focus; + 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; bool do_mouse_warp; const char *cursor_theme; @@ -211,7 +218,7 @@ class DisplayServerX11 : public DisplayServer { bool layered_window; String rendering_driver; - bool window_focused; + //bool window_focused; //void set_wm_border(bool p_enabled); void set_wm_fullscreen(bool p_enabled); void set_wm_above(bool p_enabled); @@ -231,6 +238,8 @@ class DisplayServerX11 : public DisplayServer { static Property _read_property(Display *p_display, Window p_window, Atom p_property); void _update_real_mouse_position(const WindowData &wd); + bool _window_maximize_check(WindowID p_window, const char *p_atom_name) const; + void _update_size_hints(WindowID p_window); void _set_wm_fullscreen(WindowID p_window, bool p_enabled); void _set_wm_maximized(WindowID p_window, bool p_enabled); @@ -242,6 +251,19 @@ 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(); + + 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); @@ -272,6 +294,7 @@ public: virtual Vector<DisplayServer::WindowID> get_window_list() const; 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; @@ -280,6 +303,8 @@ public: 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); + 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); 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); @@ -327,7 +352,11 @@ public: virtual CursorShape cursor_get_shape() const; virtual void cursor_set_custom_image(const RES &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot); - virtual LatinKeyboardVariant get_latin_keyboard_variant() const; + 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 void process_events(); diff --git a/platform/linuxbsd/export/export.cpp b/platform/linuxbsd/export/export.cpp index 86ea95c563..cb95068314 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 */ 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/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index 3ed64e9d46..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 */ @@ -41,6 +41,9 @@ int main(int argc, char *argv[]) { setlocale(LC_CTYPE, ""); + // We must override main when testing is enabled + TEST_MAIN_OVERRIDE + char *cwd = (char *)malloc(PATH_MAX); ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY); char *ret = getcwd(cwd, PATH_MAX); diff --git a/platform/linuxbsd/joypad_linux.cpp b/platform/linuxbsd/joypad_linux.cpp index 5edaf35c50..471259e50f 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]) { @@ -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; @@ -188,17 +202,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)) != NULL) { + 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 } @@ -311,16 +335,9 @@ void JoypadLinux::open_joypad(const char *p_path) { return; } - //check if the device supports basic gamepad events, prevents certain keyboards from - //being detected as joypads + // Check if the device supports basic gamepad events if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) && - (test_bit(ABS_X, absbit) || test_bit(ABS_Y, absbit) || test_bit(ABS_HAT0X, absbit) || - test_bit(ABS_GAS, absbit) || test_bit(ABS_RUDDER, absbit)) && - (test_bit(BTN_A, keybit) || test_bit(BTN_THUMBL, keybit) || - test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_1, keybit))) && - !(test_bit(EV_ABS, evbit) && - test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) && - test_bit(ABS_RX, absbit) && test_bit(ABS_RY, absbit))) { + test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) { close(fd); return; } @@ -466,9 +483,9 @@ void JoypadLinux::process_joypads() { case ABS_HAT0X: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad |= Input::HAT_MASK_LEFT; + joy->dpad = (joy->dpad | Input::HAT_MASK_LEFT) & ~Input::HAT_MASK_RIGHT; } else { - joy->dpad |= Input::HAT_MASK_RIGHT; + joy->dpad = (joy->dpad | Input::HAT_MASK_RIGHT) & ~Input::HAT_MASK_LEFT; } } else { joy->dpad &= ~(Input::HAT_MASK_LEFT | Input::HAT_MASK_RIGHT); @@ -480,9 +497,9 @@ void JoypadLinux::process_joypads() { case ABS_HAT0Y: if (ev.value != 0) { if (ev.value < 0) { - joy->dpad |= Input::HAT_MASK_UP; + joy->dpad = (joy->dpad | Input::HAT_MASK_UP) & ~Input::HAT_MASK_DOWN; } else { - joy->dpad |= Input::HAT_MASK_DOWN; + joy->dpad = (joy->dpad | Input::HAT_MASK_DOWN) & ~Input::HAT_MASK_UP; } } else { joy->dpad &= ~(Input::HAT_MASK_UP | Input::HAT_MASK_DOWN); diff --git a/platform/linuxbsd/joypad_linux.h b/platform/linuxbsd/joypad_linux.h index 0d175193a5..b0d0db047b 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 */ @@ -56,25 +56,27 @@ private: Input::JoyAxis curr_axis[MAX_ABS]; int key_map[MAX_KEY]; int abs_map[MAX_ABS]; - int dpad; - int fd; + int dpad = 0; + 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; diff --git a/platform/linuxbsd/key_mapping_x11.cpp b/platform/linuxbsd/key_mapping_x11.cpp index 77512b1a9e..f9f612fa74 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 */ @@ -185,7 +185,6 @@ struct _TranslatePair { }; static _TranslatePair _scancode_to_keycode[] = { - { KEY_ESCAPE, 0x09 }, { KEY_1, 0x0A }, { KEY_2, 0x0B }, @@ -354,7 +353,6 @@ struct _XTranslateUnicodePair { }; enum { - _KEYSYM_MAX = 759 }; @@ -1160,7 +1158,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..163a8e21db 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 */ 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 09a5eca914..09e1f9461c 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 */ @@ -31,8 +31,11 @@ #include "os_linuxbsd.h" #include "core/os/dir_access.h" -#include "core/print_string.h" -#include "errno.h" +#include "main/main.h" + +#ifdef X11_ENABLED +#include "display_server_x11.h" +#endif #ifdef HAVE_MNTENT #include <mntent.h> @@ -48,12 +51,6 @@ #include <sys/types.h> #include <unistd.h> -#include "main/main.h" - -#ifdef X11_ENABLED -#include "display_server_x11.h" -#endif - void OS_LinuxBSD::initialize() { crash_handler.initialize(); @@ -68,9 +65,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(); @@ -91,7 +88,9 @@ void OS_LinuxBSD::finalize() { #endif #ifdef JOYDEV_ENABLED - memdelete(joypad); + if (joypad) { + memdelete(joypad); + } #endif } @@ -124,18 +123,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; } - ok = execute("gnome-open", args, false); - if (ok == OK) { + // 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; } - ok = execute("kde-open", args, false); - return ok; + 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; + } + // KDE + ok = execute("kde-open5", args, nullptr, &err_code); + if (ok == OK && !err_code) { + 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) { @@ -212,7 +232,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 "."; } @@ -226,7 +246,7 @@ void OS_LinuxBSD::run() { return; } - main_loop->init(); + main_loop->initialize(); //uint64_t last_ticks=get_ticks_usec(); @@ -243,7 +263,7 @@ void OS_LinuxBSD::run() { } }; - main_loop->finish(); + main_loop->finalize(); } void OS_LinuxBSD::disable_crash_handler() { @@ -283,65 +303,147 @@ 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 proprely. + 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 = basename(p_path.utf8().get_data()); + if (file_name.length() > 240) { + file_name = file_name.substr(0, file_name.length() - 15); + } + + 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, date.month, date.day, time.hour, time.min); + timestamp = vformat("%s%02d", timestamp, time.sec); // 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); } - // The trash can is successfully created, now move the given resource to it. + // 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 4295721c68..b6cf93c551 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,16 +39,16 @@ #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; #ifdef JOYDEV_ENABLED - JoypadLinux *joypad; + JoypadLinux *joypad = nullptr; #endif #ifdef ALSA_ENABLED @@ -68,36 +68,36 @@ 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) 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 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 ac30519132..3195d08935 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 */ @@ -31,9 +31,15 @@ #ifdef __linux__ #include <alloca.h> #endif -#if defined(__FreeBSD__) || defined(__OpenBSD__) -#include <stdlib.h> + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#include <stdlib.h> // alloca +// FreeBSD and OpenBSD use pthread_set_name_np, while other platforms, +// include NetBSD, use pthread_setname_np. NetBSD's version however requires +// a different format, we handle this directly in thread_posix. +#ifdef __NetBSD__ +#define PTHREAD_NETBSD_SET_NAME +#else #define PTHREAD_BSD_SET_NAME #endif - -#define GLES2_INCLUDE_H "thirdparty/glad/glad/glad.h" +#endif diff --git a/platform/linuxbsd/vulkan_context_x11.cpp b/platform/linuxbsd/vulkan_context_x11.cpp index 2eaa9f9446..021db630e0 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 */ diff --git a/platform/linuxbsd/vulkan_context_x11.h b/platform/linuxbsd/vulkan_context_x11.h index af3d923cfe..26472444ad 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 */ |