From 97f5bbfe00adc144cc974b5849d7c53dc8bd30eb Mon Sep 17 00:00:00 2001 From: Medusa Slockbower Date: Mon, 15 Dec 2025 16:29:00 -0500 Subject: [PATCH] - Windows now use libdecor when present. --- .../linux/wayland/libdecor/libdecor.h | 80 +++++------ .../platform/linux/wayland/libdecor/sym.h | 8 -- .../fennec/platform/linux/wayland/server.h | 29 +++- .../fennec/platform/linux/wayland/window.h | 34 +++-- source/platform/linux/wayland/server.cpp | 51 +++++-- source/platform/linux/wayland/window.cpp | 125 ++++++++++++++---- 6 files changed, 225 insertions(+), 102 deletions(-) diff --git a/include/fennec/platform/linux/wayland/libdecor/libdecor.h b/include/fennec/platform/linux/wayland/libdecor/libdecor.h index e24179a..8c2bc49 100644 --- a/include/fennec/platform/linux/wayland/libdecor/libdecor.h +++ b/include/fennec/platform/linux/wayland/libdecor/libdecor.h @@ -29,52 +29,52 @@ /// -#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LIBDECOR_H -#define FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LIBDECOR_H +#ifndef FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H +#define FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H +#include #include #define FENNEC_LIB(name) extern "C" bool FENNEC_HAS_LIB_##name; #define FENNEC_SYMBOL(ret, fn, ...) using LIBDECOR_sym_##fn = ret(*)(__VA_ARGS__); \ - extern "C" LIBDECOR_sym_##fn WAYLAND_##fn; + extern "C" LIBDECOR_sym_##fn LIBDECOR_##fn; #define FENNEC_GLOBAL(type, name) extern "C" type* LIBDECOR_##name; #include -#define libdecor_unref WAYLAND_libdecor_unref -#define libdecor_new WAYLAND_libdecor_new -#define libdecor_decorate WAYLAND_libdecor_decorate -#define libdecor_frame_unref WAYLAND_libdecor_frame_unref -#define libdecor_frame_set_title WAYLAND_libdecor_frame_set_title -#define libdecor_frame_set_app_id WAYLAND_libdecor_frame_set_app_id -#define libdecor_frame_set_max_content_size WAYLAND_libdecor_frame_set_max_content_size -#define libdecor_frame_get_max_content_size WAYLAND_libdecor_frame_get_max_content_size -#define libdecor_frame_set_min_content_size WAYLAND_libdecor_frame_set_min_content_size -#define libdecor_frame_get_min_content_size WAYLAND_libdecor_frame_get_min_content_size -#define libdecor_frame_resize WAYLAND_libdecor_frame_resize -#define libdecor_frame_move WAYLAND_libdecor_frame_move -#define libdecor_frame_commit WAYLAND_libdecor_frame_commit -#define libdecor_frame_set_minimized WAYLAND_libdecor_frame_set_minimized -#define libdecor_frame_set_maximized WAYLAND_libdecor_frame_set_maximized -#define libdecor_frame_unset_maximized WAYLAND_libdecor_frame_unset_maximized -#define libdecor_frame_set_fullscreen WAYLAND_libdecor_frame_set_fullscreen -#define libdecor_frame_unset_fullscreen WAYLAND_libdecor_frame_unset_fullscreen -#define libdecor_frame_set_capabilities WAYLAND_libdecor_frame_set_capabilities -#define libdecor_frame_unset_capabilities WAYLAND_libdecor_frame_unset_capabilities -#define libdecor_frame_has_capability WAYLAND_libdecor_frame_has_capability -#define libdecor_frame_set_visibility WAYLAND_libdecor_frame_set_visibility -#define libdecor_frame_is_visible WAYLAND_libdecor_frame_is_visible -#define libdecor_frame_is_floating WAYLAND_libdecor_frame_is_floating -#define libdecor_frame_set_parent WAYLAND_libdecor_frame_set_parent -#define libdecor_frame_show_window_menu WAYLAND_libdecor_frame_show_window_menu -#define libdecor_frame_get_wm_capabilities WAYLAND_libdecor_frame_get_wm_capabilities -#define libdecor_frame_get_xdg_surface WAYLAND_libdecor_frame_get_xdg_surface -#define libdecor_frame_get_xdg_toplevel WAYLAND_libdecor_frame_get_xdg_toplevel -#define libdecor_frame_translate_coordinate WAYLAND_libdecor_frame_translate_coordinate -#define libdecor_frame_map WAYLAND_libdecor_frame_map -#define libdecor_state_new WAYLAND_libdecor_state_new -#define libdecor_state_free WAYLAND_libdecor_state_free -#define libdecor_configuration_get_content_size WAYLAND_libdecor_configuration_get_content_size -#define libdecor_configuration_get_window_state WAYLAND_libdecor_configuration_get_window_state -#define libdecor_dispatch WAYLAND_libdecor_dispatch +#define libdecor_unref LIBDECOR_libdecor_unref +#define libdecor_new LIBDECOR_libdecor_new +#define libdecor_decorate LIBDECOR_libdecor_decorate +#define libdecor_frame_unref LIBDECOR_libdecor_frame_unref +#define libdecor_frame_set_title LIBDECOR_libdecor_frame_set_title +#define libdecor_frame_set_app_id LIBDECOR_libdecor_frame_set_app_id +#define libdecor_frame_set_max_content_size LIBDECOR_libdecor_frame_set_max_content_size +#define libdecor_frame_get_max_content_size LIBDECOR_libdecor_frame_get_max_content_size +#define libdecor_frame_set_min_content_size LIBDECOR_libdecor_frame_set_min_content_size +#define libdecor_frame_get_min_content_size LIBDECOR_libdecor_frame_get_min_content_size +#define libdecor_frame_resize LIBDECOR_libdecor_frame_resize +#define libdecor_frame_move LIBDECOR_libdecor_frame_move +#define libdecor_frame_commit LIBDECOR_libdecor_frame_commit +#define libdecor_frame_set_minimized LIBDECOR_libdecor_frame_set_minimized +#define libdecor_frame_set_maximized LIBDECOR_libdecor_frame_set_maximized +#define libdecor_frame_unset_maximized LIBDECOR_libdecor_frame_unset_maximized +#define libdecor_frame_set_fullscreen LIBDECOR_libdecor_frame_set_fullscreen +#define libdecor_frame_unset_fullscreen LIBDECOR_libdecor_frame_unset_fullscreen +#define libdecor_frame_set_capabilities LIBDECOR_libdecor_frame_set_capabilities +#define libdecor_frame_unset_capabilities LIBDECOR_libdecor_frame_unset_capabilities +#define libdecor_frame_has_capability LIBDECOR_libdecor_frame_has_capability +#define libdecor_frame_set_visibility LIBDECOR_libdecor_frame_set_visibility +#define libdecor_frame_is_visible LIBDECOR_libdecor_frame_is_visible +#define libdecor_frame_is_floating LIBDECOR_libdecor_frame_is_floating +#define libdecor_frame_set_parent LIBDECOR_libdecor_frame_set_parent +#define libdecor_frame_show_window_menu LIBDECOR_libdecor_frame_show_window_menu +#define libdecor_frame_get_xdg_surface LIBDECOR_libdecor_frame_get_xdg_surface +#define libdecor_frame_get_xdg_toplevel LIBDECOR_libdecor_frame_get_xdg_toplevel +#define libdecor_frame_translate_coordinate LIBDECOR_libdecor_frame_translate_coordinate +#define libdecor_frame_map LIBDECOR_libdecor_frame_map +#define libdecor_state_new LIBDECOR_libdecor_state_new +#define libdecor_state_free LIBDECOR_libdecor_state_free +#define libdecor_configuration_get_content_size LIBDECOR_libdecor_configuration_get_content_size +#define libdecor_configuration_get_window_state LIBDECOR_libdecor_configuration_get_window_state +#define libdecor_dispatch LIBDECOR_libdecor_dispatch -#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_LIBDECOR_H \ No newline at end of file +#endif // FENNEC_PLATFORM_LINUX_WAYLAND_LIBDECOR_H \ No newline at end of file diff --git a/include/fennec/platform/linux/wayland/libdecor/sym.h b/include/fennec/platform/linux/wayland/libdecor/sym.h index 72511dc..f308658 100644 --- a/include/fennec/platform/linux/wayland/libdecor/sym.h +++ b/include/fennec/platform/linux/wayland/libdecor/sym.h @@ -83,14 +83,6 @@ FENNEC_SYMBOL(bool, libdecor_configuration_get_window_state, struct libdecor_con enum libdecor_window_state*) - - - - - - - - #undef FENNEC_LIB #undef FENNEC_SYMBOL #undef FENNEC_GLOBAL \ No newline at end of file diff --git a/include/fennec/platform/linux/wayland/server.h b/include/fennec/platform/linux/wayland/server.h index d8564ad..daee9fe 100644 --- a/include/fennec/platform/linux/wayland/server.h +++ b/include/fennec/platform/linux/wayland/server.h @@ -34,6 +34,10 @@ #include #include +#if FENNEC_HAS_LIBDECOR +#include +#endif + // forward defs to avoid flooding global namespace struct wl_display; struct wl_shm; @@ -64,6 +68,8 @@ public: void* get_native_handle() override { return display; } + +// Fields ============================================================================================================== private: wl_display* display; wl_registry* registry; @@ -71,15 +77,26 @@ private: wl_compositor* compositor; xdg_wm_base* xdg; wl_seat* seat; - bool fifo, libdecor; + bool fifo, has_libdecor; - static void listen_global(void*, wl_registry*, uint32_t, const char*, uint32_t); - static void listen_global_remove(void*, wl_registry*, uint32_t); +#if FENNEC_HAS_LIBDECOR + libdecor* libdecor; +#endif - static void listen_seat_capabilities(void*, wl_seat*, uint32_t); - static void listen_seat_name(void*, wl_seat*, const char*); - static void listen_xdg_ping(void*, xdg_wm_base*, uint32_t); +// Listeners =========================================================================================================== + + static void _wl_registry_listen_global(void*, wl_registry*, uint32_t, const char*, uint32_t); + static void _wl_registry_on_global_remove(void*, wl_registry*, uint32_t); + + static void _wl_seat_listen_capabilities(void*, wl_seat*, uint32_t); + static void _wl_seat_listen_name(void*, wl_seat*, const char*); + + static void _xdg_listen_ping(void*, xdg_wm_base*, uint32_t); + +#if FENNEC_HAS_LIBDECOR + static void _libdecor_on_error(struct libdecor*, libdecor_error error, const char* message); +#endif FENNEC_RTTI_CLASS_ENABLE(display_server) { display_server::register_type(1); diff --git a/include/fennec/platform/linux/wayland/window.h b/include/fennec/platform/linux/wayland/window.h index cb1ef7a..9b4dfd7 100644 --- a/include/fennec/platform/linux/wayland/window.h +++ b/include/fennec/platform/linux/wayland/window.h @@ -42,6 +42,9 @@ struct wl_surface; struct xdg_surface; struct xdg_toplevel; +struct libdecor_frame; +struct libdecor_configuration; + namespace fennec { @@ -63,19 +66,30 @@ private: xdg_toplevel* xdgtoplevel; wl_callback* frame_callback; - static void listen_enter(void*, wl_surface*, wl_output*); - static void listen_leave(void*, wl_surface*, wl_output*); - static void listen_preferred_buffer_scale(void*, wl_surface*, int32_t); - static void listen_preferred_buffer_transform(void*, wl_surface*, uint32_t); +#if FENNEC_HAS_LIBDECOR + libdecor_frame* libdecorframe; +#endif - static void listen_frame_callback(void*, wl_callback*, uint32_t); + static void _wl_surface_listen_enter(void*, wl_surface*, wl_output*); + static void _wl_surface_listen_leave(void*, wl_surface*, wl_output*); + static void _wl_surface_listen_preferred_buffer_scale(void*, wl_surface*, int32_t); + static void _wl_surface_listen_preferred_buffer_transform(void*, wl_surface*, uint32_t); - static void listen_xdg_surface_configure(void*, xdg_surface*, uint32_t); + static void _wl_frame_listen_done(void*, wl_callback*, uint32_t); - static void listen_xdg_toplevel_configure(void*, xdg_toplevel*, int32_t, int32_t, wl_array*); - static void listen_xdg_toplevel_configure_bounds(void*, xdg_toplevel*, int32_t, int32_t); - static void listen_xdg_toplevel_close(void*, xdg_toplevel*); - static void listen_xdg_toplevel_capabilities(void*, xdg_toplevel*, wl_array*); + static void _xdg_surface_listen_configure(void*, xdg_surface*, uint32_t); + + static void _xdg_toplevel_listen_configure(void*, xdg_toplevel*, int32_t, int32_t, wl_array*); + static void _xdg_toplevel_listen_configure_bounds(void*, xdg_toplevel*, int32_t, int32_t); + static void _xdg_toplevel_listen_close(void*, xdg_toplevel*); + static void _xdg_toplevel_listen_wm_capabilities(void*, xdg_toplevel*, wl_array*); + +#if FENNEC_HAS_LIBDECOR + static void _libdecor_frame_listen_configure(libdecor_frame*, libdecor_configuration*, void*); + static void _libdecor_frame_listen_close(libdecor_frame*, void*); + static void _libdecor_frame_listen_commit(libdecor_frame*, void*); + static void _libdecor_frame_listen_dismiss_popup(libdecor_frame*, const char*, void*); +#endif }; } diff --git a/source/platform/linux/wayland/server.cpp b/source/platform/linux/wayland/server.cpp index 3bdb3fb..b57e3fa 100644 --- a/source/platform/linux/wayland/server.cpp +++ b/source/platform/linux/wayland/server.cpp @@ -23,8 +23,8 @@ #include #include -#include #include +#include #include #if FENNEC_HAS_LIBDECOR @@ -36,13 +36,13 @@ namespace fennec wayland_server::wayland_server(fennec::platform* p) : display_server_base(p) - , display(nullptr), registry(nullptr), compositor(nullptr), seat(nullptr), fifo(false), libdecor(false) { + , display(nullptr), registry(nullptr), compositor(nullptr), seat(nullptr), fifo(false), has_libdecor(false) { // load shared lib assertf(libwayland::load_symbols(platform), "Failed to load libwayland."); #if FENNEC_HAS_LIBDECOR - libdecor = libdecor::load_symbols(platform); + has_libdecor = libdecor::load_symbols(platform); #endif } @@ -58,7 +58,7 @@ wayland_server::~wayland_server() { void wayland_server::connect() { static constexpr wl_registry_listener listener = { - listen_global, listen_global_remove + _wl_registry_listen_global, _wl_registry_on_global_remove }; if (display != nullptr) { @@ -90,6 +90,27 @@ void wayland_server::connect() { return; } +#if FENNEC_HAS_LIBDECOR + static libdecor_interface libdecor_listener = { + .error = _libdecor_on_error, + + .reserved0 = nullptr, + .reserved1 = nullptr, + .reserved2 = nullptr, + .reserved3 = nullptr, + .reserved4 = nullptr, + .reserved5 = nullptr, + .reserved6 = nullptr, + .reserved7 = nullptr, + .reserved8 = nullptr, + .reserved9 = nullptr, + }; + + if (has_libdecor) { + libdecor = libdecor_new(display, &libdecor_listener); + } +#endif + auto contexts = ctx_registry::get_type_list(); while (not contexts.empty()) { const auto& ctx = contexts.front(); @@ -154,13 +175,13 @@ window* wayland_server::create_window(const window::config& conf) { return windows[id]; } -void wayland_server::listen_global(void* data, wl_registry* reg, uint32_t id, const char* name, uint32_t version) { +void wayland_server::_wl_registry_listen_global(void* data, wl_registry* reg, uint32_t id, const char* name, uint32_t version) { static constexpr wl_seat_listener seat_listener = { - listen_seat_capabilities, listen_seat_name + _wl_seat_listen_capabilities, _wl_seat_listen_name }; static constexpr xdg_wm_base_listener xdg_listener = { - listen_xdg_ping + _xdg_listen_ping }; wayland_server* server = static_cast(data); @@ -189,20 +210,28 @@ void wayland_server::listen_global(void* data, wl_registry* reg, uint32_t id, co } } -void wayland_server::listen_global_remove(void*, wl_registry*, uint32_t) { +void wayland_server::_wl_registry_on_global_remove(void*, wl_registry*, uint32_t) { } -void wayland_server::listen_seat_capabilities(void*, wl_seat*, uint32_t) { +void wayland_server::_wl_seat_listen_capabilities(void*, wl_seat*, uint32_t) { } -void wayland_server::listen_seat_name(void*, wl_seat*, const char*) {} +void wayland_server::_wl_seat_listen_name(void*, wl_seat*, const char*) {} -void wayland_server::listen_xdg_ping(void*, xdg_wm_base* xdg, uint32_t serial) { +void wayland_server::_xdg_listen_ping(void*, xdg_wm_base* xdg, uint32_t serial) { xdg_wm_base_pong(xdg, serial); } +#if FENNEC_HAS_LIBDECOR +void wayland_server::_libdecor_on_error(struct libdecor*, libdecor_error error, const char* message) { + fennec::logger::log( + fennec::format("libdecor error ({}): {}", static_cast(error), fennec::cstring(message, strlen(message))) + ); +} +#endif + } diff --git a/source/platform/linux/wayland/window.cpp b/source/platform/linux/wayland/window.cpp index 712ff80..9b75aaa 100644 --- a/source/platform/linux/wayland/window.cpp +++ b/source/platform/linux/wayland/window.cpp @@ -18,11 +18,16 @@ #include +#include + #include #include #include #include -#include + +#if FENNEC_HAS_LIBDECOR +#include +#endif using namespace fennec; @@ -39,20 +44,25 @@ wayland_window::~wayland_window() { void wayland_window::show() { static constexpr wl_surface_listener surface_listener = { - listen_enter, listen_leave, listen_preferred_buffer_scale, listen_preferred_buffer_transform + .enter = _wl_surface_listen_enter, + .leave = _wl_surface_listen_leave, + .preferred_buffer_scale = _wl_surface_listen_preferred_buffer_scale, + .preferred_buffer_transform = _wl_surface_listen_preferred_buffer_transform }; static constexpr xdg_surface_listener xdg_surface_listener = { - listen_xdg_surface_configure + .configure = _xdg_surface_listen_configure }; static constexpr xdg_toplevel_listener xdg_toplevel_listener = { - listen_xdg_toplevel_configure, listen_xdg_toplevel_close, listen_xdg_toplevel_configure_bounds, - listen_xdg_toplevel_capabilities + .configure = _xdg_toplevel_listen_configure, + .close = _xdg_toplevel_listen_close, + .configure_bounds = _xdg_toplevel_listen_configure_bounds, + .wm_capabilities = _xdg_toplevel_listen_wm_capabilities }; static constexpr wl_callback_listener frame_callback_listener = { - listen_frame_callback + .done = _wl_frame_listen_done }; if (is_visible()) { @@ -77,15 +87,42 @@ void wayland_window::show() { surface = wl_compositor_create_surface(wl_server->compositor); wl_surface_add_listener(surface, &surface_listener, this); +#if FENNEC_HAS_LIBDECOR + static libdecor_frame_interface libdecor_frame_listener = { + .configure = _libdecor_frame_listen_configure, + .close = _libdecor_frame_listen_close, + .commit = _libdecor_frame_listen_commit, + .dismiss_popup = _libdecor_frame_listen_dismiss_popup, - xdgsurface = xdg_wm_base_get_xdg_surface(wl_server->xdg, surface); - xdg_surface_add_listener(xdgsurface, &xdg_surface_listener, this); + .reserved0 = nullptr, + .reserved1 = nullptr, + .reserved2 = nullptr, + .reserved3 = nullptr, + .reserved4 = nullptr, + .reserved5 = nullptr, + .reserved6 = nullptr, + .reserved7 = nullptr, + .reserved8 = nullptr, + .reserved9 = nullptr, + }; - xdgtoplevel = xdg_surface_get_toplevel(xdgsurface); - xdg_toplevel_add_listener(xdgtoplevel, &xdg_toplevel_listener, this); + if (wl_server->has_libdecor) { + + libdecorframe = libdecor_decorate(wl_server->libdecor, surface, &libdecor_frame_listener, this); + libdecor_frame_map(libdecorframe); + + xdgsurface = libdecor_frame_get_xdg_surface(libdecorframe); + xdgtoplevel = libdecor_frame_get_xdg_toplevel(libdecorframe); + + } else +#endif + { + xdgsurface = xdg_wm_base_get_xdg_surface(wl_server->xdg, surface); + xdg_surface_add_listener(xdgsurface, &xdg_surface_listener, this); + + xdgtoplevel = xdg_surface_get_toplevel(xdgsurface); + xdg_toplevel_add_listener(xdgtoplevel, &xdg_toplevel_listener, this); - if (has_decorations()) { - } @@ -109,16 +146,24 @@ void wayland_window::hide() { wayland_server* wl_server = static_cast(server); - if (xdgtoplevel) { - xdg_toplevel_destroy(xdgtoplevel); - xdgtoplevel = nullptr; - } - if (frame_callback) { wl_callback_destroy(frame_callback); frame_callback = nullptr; } +#if FENNEC_HAS_LIBDECOR + if (libdecorframe) { + libdecor_frame_unref(libdecorframe); + xdgtoplevel = nullptr; + xdgsurface = nullptr; + } +#endif + + if (xdgtoplevel) { + xdg_toplevel_destroy(xdgtoplevel); + xdgtoplevel = nullptr; + } + if (xdgsurface) { xdg_surface_destroy(xdgsurface); xdgsurface = nullptr; @@ -143,24 +188,50 @@ bool wayland_window::set_flag(uint8_t, bool) { return false; } -void wayland_window::listen_enter(void*, wl_surface*, wl_output*) {} -void wayland_window::listen_leave(void*, wl_surface*, wl_output*) {} -void wayland_window::listen_preferred_buffer_scale(void*, wl_surface*, int32_t) {} -void wayland_window::listen_preferred_buffer_transform(void*, wl_surface*, uint32_t) {} +// Surface Listeners -void wayland_window::listen_frame_callback(void*, wl_callback*, uint32_t) {} +void wayland_window::_wl_surface_listen_enter(void*, wl_surface*, wl_output*) {} +void wayland_window::_wl_surface_listen_leave(void*, wl_surface*, wl_output*) {} +void wayland_window::_wl_surface_listen_preferred_buffer_scale(void*, wl_surface*, int32_t) {} +void wayland_window::_wl_surface_listen_preferred_buffer_transform(void*, wl_surface*, uint32_t) {} -void wayland_window::listen_xdg_surface_configure(void*, xdg_surface* xdg, uint32_t serial) { + +// Frame Listeners + +void wayland_window::_wl_frame_listen_done(void*, wl_callback*, uint32_t) {} + + +// XDG Listeners + +void wayland_window::_xdg_surface_listen_configure(void*, xdg_surface* xdg, uint32_t serial) { xdg_surface_ack_configure(xdg, serial); } -void wayland_window::listen_xdg_toplevel_configure(void*, xdg_toplevel*, int32_t, int32_t, wl_array*) {} -void wayland_window::listen_xdg_toplevel_configure_bounds(void*, xdg_toplevel*, int32_t, int32_t) {} +void wayland_window::_xdg_toplevel_listen_configure(void*, xdg_toplevel*, int32_t, int32_t, wl_array*) {} +void wayland_window::_xdg_toplevel_listen_configure_bounds(void*, xdg_toplevel*, int32_t, int32_t) {} -void wayland_window::listen_xdg_toplevel_close(void* data, xdg_toplevel*) { +void wayland_window::_xdg_toplevel_listen_close(void* data, xdg_toplevel*) { wayland_window* window = static_cast(data); window->hide(); } -void wayland_window::listen_xdg_toplevel_capabilities(void*, xdg_toplevel*, wl_array*) {} +void wayland_window::_xdg_toplevel_listen_wm_capabilities(void*, xdg_toplevel*, wl_array*) {} + + +// Libdecor Listeners + +#if FENNEC_HAS_LIBDECOR + +void wayland_window::_libdecor_frame_listen_configure(libdecor_frame*, libdecor_configuration*, void*) {} + +void wayland_window::_libdecor_frame_listen_close(libdecor_frame*, void* data) { + wayland_window* window = static_cast(data); + window->hide(); +} + +void wayland_window::_libdecor_frame_listen_commit(libdecor_frame*, void*) {} +void wayland_window::_libdecor_frame_listen_dismiss_popup(libdecor_frame*, const char*, void*) {} + +#endif +