diff --git a/src/gl/inject_egl.cpp b/src/gl/inject_egl.cpp index d49447dc13..17f7b8504b 100644 --- a/src/gl/inject_egl.cpp +++ b/src/gl/inject_egl.cpp @@ -97,10 +97,9 @@ EXPORT_C_(void*) eglGetPlatformDisplay( unsigned int platform, void* native_disp #ifdef HAVE_WAYLAND if(platform == EGL_PLATFORM_WAYLAND_KHR) { - wl_display_ptr = (struct wl_display*)native_display; + wl_display* display = static_cast(native_display); HUDElements.display_server = HUDElements.display_servers::WAYLAND; - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY); - init_wayland_data(); + init_wayland_data(display); } #endif @@ -117,14 +116,12 @@ EXPORT_C_(void*) eglGetDisplay( void* native_display ) #ifdef HAVE_WAYLAND try { - void** display_ptr = (void**)native_display; - wl_interface* iface = (wl_interface*)*display_ptr; + wl_interface* iface = *static_cast(native_display); if(iface && strcmp(iface->name, wl_display_interface.name) == 0) { - wl_display_ptr = (struct wl_display*)native_display; + wl_display* display = static_cast(native_display); HUDElements.display_server = HUDElements.display_servers::WAYLAND; - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY); - init_wayland_data(); + init_wayland_data(display); } } catch(...) @@ -135,17 +132,32 @@ EXPORT_C_(void*) eglGetDisplay( void* native_display ) return pfn_eglGetDisplay(native_display); } +EXPORT_C_(unsigned) eglTerminate( void* native_display ); +EXPORT_C_(unsigned) eglTerminate( void* native_display ) +{ + static unsigned (*pfn_eglTerminate)(void*) = nullptr; + if (!pfn_eglTerminate) + pfn_eglTerminate= reinterpret_cast(get_egl_proc_address("eglTerminate")); + +#ifdef HAVE_WAYLAND + fini_wayland_data(); +#endif + + return pfn_eglTerminate(native_display); +} + struct func_ptr { const char *name; void *ptr; }; -static std::array name_to_funcptr_map = {{ +static std::array name_to_funcptr_map = {{ #define ADD_HOOK(fn) { #fn, (void *) fn } ADD_HOOK(eglGetProcAddress), ADD_HOOK(eglSwapBuffers), ADD_HOOK(eglGetPlatformDisplay), - ADD_HOOK(eglGetDisplay) + ADD_HOOK(eglGetDisplay), + ADD_HOOK(eglTerminate) #undef ADD_HOOK }}; diff --git a/src/keybinds.h b/src/keybinds.h index 4c5057004f..1c041e57c0 100644 --- a/src/keybinds.h +++ b/src/keybinds.h @@ -18,14 +18,8 @@ typedef unsigned long KeySym; static inline bool keys_are_pressed(const std::vector& keys) { #if defined(HAVE_WAYLAND) - if(wl_display_ptr && wl_handle) - { - update_wl_queue(); - - if(wl_pressed_keys == keys) - { - return true; - } + if (any_wayland_seat_syms_are_pressed(keys)) { + return true; } #endif diff --git a/src/vulkan.cpp b/src/vulkan.cpp index e9f896cd03..1391deb9e0 100644 --- a/src/vulkan.cpp +++ b/src/vulkan.cpp @@ -2031,6 +2031,9 @@ static void overlay_DestroyInstance( stop_notifier(instance_data->notifier); #endif destroy_instance_data(instance_data); +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + fini_wayland_data(); +#endif } #ifdef VK_USE_PLATFORM_WAYLAND_KHR @@ -2042,11 +2045,8 @@ static VkResult overlay_CreateWaylandSurfaceKHR( ) { struct instance_data *instance_data = FIND(struct instance_data, instance); - if (!wl_handle) - wl_handle = real_dlopen("libwayland-client.so", RTLD_LAZY); - wl_display_ptr = pCreateInfo->display; HUDElements.display_server = HUDElements.display_servers::WAYLAND; - init_wayland_data(); + init_wayland_data(pCreateInfo->display); return instance_data->vtable.CreateWaylandSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface); } #endif diff --git a/src/wayland_hook.h b/src/wayland_hook.h index c637e7243b..33495ecb2a 100644 --- a/src/wayland_hook.h +++ b/src/wayland_hook.h @@ -1,13 +1,18 @@ -#include +#pragma once +#ifndef MANGOHUD_WAYLAND_HOOK_H +#define MANGOHUD_WAYLAND_HOOK_H + #include +struct wl_display; + #ifndef KeySym typedef unsigned long KeySym; #endif -extern void* wl_handle; -extern struct wl_display* wl_display_ptr; -extern std::vector wl_pressed_keys; +void init_wayland_data(wl_display *display); +void fini_wayland_data(); -void init_wayland_data(); -void update_wl_queue(); +bool any_wayland_seat_syms_are_pressed(const std::vector &syms); + +#endif diff --git a/src/wayland_keybinds.cpp b/src/wayland_keybinds.cpp index d18cbf15fa..a9c1fc7636 100644 --- a/src/wayland_keybinds.cpp +++ b/src/wayland_keybinds.cpp @@ -3,136 +3,308 @@ #include #include #include -#include -#include -#include #include + #include "wayland_hook.h" -#include "timing.hpp" #include "keybinds.h" -void* wl_handle = nullptr; -struct wl_display* wl_display_ptr = nullptr; -struct wl_seat* seat = nullptr; -struct wl_keyboard* keyboard = nullptr; -struct xkb_context *context_xkb = nullptr; -struct xkb_keymap *keymap_xkb = nullptr; -struct xkb_state *state_xkb = nullptr; -struct wl_event_queue* queue = nullptr; -std::vector wl_pressed_keys {}; - -static void seat_handle_capabilities(void *data, wl_seat *seat, uint32_t caps); -static void seat_handle_name(void *data, struct wl_seat *seat, const char *name) {} - -struct wl_seat_listener seat_listener { - .capabilities = seat_handle_capabilities, - .name = seat_handle_name, +#include +#include + +#define SEAT_MAX_VERSION 5 + +class SeatInfo +{ +public: + SeatInfo(uint32_t name, wl_seat *seat); + SeatInfo(const SeatInfo &info) = delete; + SeatInfo(const SeatInfo &&info) = delete; + ~SeatInfo(); + + bool is_global(uint32_t name) const; + bool are_pressed(const std::vector &syms) const; + + void init_keyboard(); + void fini_keyboard(); + + void keymap(uint32_t format, int fd, size_t size); + void key(uint32_t key, uint32_t state); + void modifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group); + + void clear(); + +private: + uint32_t _name; + wl_seat *_seat; + wl_keyboard *_keyboard; + xkb_state *_xkb_state; + std::vector _pressed_syms; }; -static void registry_handle_global(void *data, struct wl_registry* registry, uint32_t name, const char *interface, uint32_t version) +static wl_display *wl_display_ptr = nullptr; +static wl_event_queue *wl_queue_ptr = nullptr; +static wl_registry *wl_registry_ptr = nullptr; +static xkb_context *xkb_context = nullptr; +static std::vector> seats {}; + +static void wl_keyboard_keymap(void *data, wl_keyboard *, uint32_t format, int32_t fd, uint32_t size) { - if(strcmp(interface, wl_seat_interface.name) == 0 && !seat) - { - seat = (struct wl_seat*)wl_registry_bind(registry, name, &wl_seat_interface, 5); - wl_seat_add_listener(seat, &seat_listener, NULL); - } + static_cast(data)->keymap(format, fd, size); } -static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name){} +static void wl_keyboard_enter(void *, wl_keyboard *, uint32_t, wl_surface *, wl_array *) { } -static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard, uint32_t format, int32_t fd, uint32_t size) +static void wl_keyboard_leave(void *data, wl_keyboard *, uint32_t , wl_surface *) { - char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + static_cast(data)->clear(); +} - if(!context_xkb) - context_xkb = xkb_context_new(XKB_CONTEXT_NO_FLAGS); +static void wl_keyboard_key(void *data, wl_keyboard *, uint32_t, uint32_t, uint32_t key, uint32_t state) +{ + static_cast(data)->key(key, state); +} - if(keymap_xkb && state_xkb) - { - xkb_keymap_unref(keymap_xkb); - xkb_state_unref(state_xkb); - } +static void wl_keyboard_modifiers(void *data, wl_keyboard *, uint32_t, uint32_t depressed, uint32_t latched, + uint32_t locked, uint32_t group) +{ + static_cast(data)->modifiers(depressed, latched, locked, group); +} - keymap_xkb = xkb_keymap_new_from_string( - context_xkb, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, - XKB_KEYMAP_COMPILE_NO_FLAGS); +static void wl_keyboard_repeat_info(void *, wl_keyboard *, int32_t, int32_t) { } - state_xkb = xkb_state_new(keymap_xkb); +static wl_keyboard_listener keyboard_listener { + .keymap = wl_keyboard_keymap, + .enter = wl_keyboard_enter, + .leave = wl_keyboard_leave, + .key = wl_keyboard_key, + .modifiers = wl_keyboard_modifiers, + .repeat_info = wl_keyboard_repeat_info +}; - munmap((void*)map_shm, size); - close(fd); +static void seat_handle_capabilities(void *data, wl_seat *, uint32_t caps) +{ + auto info = static_cast(data); + if (caps & WL_SEAT_CAPABILITY_KEYBOARD) + info->init_keyboard(); + else + info->fini_keyboard(); } -static void wl_keyboard_enter(void *user_data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys){} +static void seat_handle_name(void *, wl_seat *, const char *) {} -static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, struct wl_surface *surface) +static wl_seat_listener seat_listener { + .capabilities = seat_handle_capabilities, + .name = seat_handle_name, +}; + +static void registry_handle_global(void *, wl_registry *registry, uint32_t name, const char *interface, + uint32_t version) { - wl_pressed_keys.clear(); + if (strcmp(interface, wl_seat_interface.name) == 0) { + if (version > SEAT_MAX_VERSION) + version = SEAT_MAX_VERSION; + + auto seat = static_cast(wl_registry_bind(registry, name, &wl_seat_interface, version)); + if (seat) + seats.push_back(std::make_unique(name, seat)); + } } -static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state) +static void registry_handle_global_remove(void *data, wl_registry *, uint32_t name) { - xkb_keycode_t keycode = key + 8; - xkb_keysym_t keysym = xkb_state_key_get_one_sym(state_xkb, keycode); + auto it = std::find_if( + seats.begin(), + seats.end(), + [&name](const std::unique_ptr &s) + { + return s->is_global(name); + }); - if(state) - { - wl_pressed_keys.push_back(keysym); - } - else - { - auto it = std::find(wl_pressed_keys.begin(), wl_pressed_keys.end(), keysym); - if(it != wl_pressed_keys.end()) - wl_pressed_keys.erase(it); - } + if (it != seats.end()) + seats.erase(it); } -static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group){} +static wl_registry_listener registry_listener{ + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; -static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay){} -struct wl_registry_listener registry_listener { - .global = registry_handle_global, - .global_remove = registry_handle_global_remove -}; +SeatInfo::SeatInfo(uint32_t name, wl_seat *seat) + : _name(name), _seat(seat), _keyboard(nullptr), + _xkb_state(nullptr), _pressed_syms() +{ + wl_seat_add_listener(seat, &seat_listener, this); +} -struct wl_keyboard_listener keyboard_listener { - .keymap = wl_keyboard_keymap, - .enter = wl_keyboard_enter, - .leave = wl_keyboard_leave, - .key = wl_keyboard_key, - .modifiers = wl_keyboard_modifiers, - .repeat_info = wl_keyboard_repeat_info -}; +SeatInfo::~SeatInfo() +{ + fini_keyboard(); + + if (wl_seat_get_version(_seat) >= WL_SEAT_RELEASE_SINCE_VERSION) + wl_seat_release(_seat); + else + wl_seat_destroy(_seat); +} + +bool SeatInfo::is_global(uint32_t name) const +{ + return _name == name; +} + +bool SeatInfo::are_pressed(const std::vector &syms) const +{ + return syms == _pressed_syms; +} -static void seat_handle_capabilities(void *data, wl_seat *seat, uint32_t caps) +void SeatInfo::init_keyboard() { - if(caps & WL_SEAT_CAPABILITY_KEYBOARD) - { - if(!keyboard) - { - keyboard = wl_seat_get_keyboard(seat); - wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL); - } - } + if (_keyboard) + return; + + _keyboard = wl_seat_get_keyboard(_seat); + if (_keyboard) + wl_keyboard_add_listener(_keyboard, &keyboard_listener, this); +} + +void SeatInfo::fini_keyboard() +{ + if (!_keyboard) + return; + + xkb_state_unref(_xkb_state); + _xkb_state = nullptr; + + if (wl_keyboard_get_version(_keyboard) >= WL_KEYBOARD_RELEASE_SINCE_VERSION) + wl_keyboard_release(_keyboard); + else + wl_keyboard_destroy(_keyboard); + + _keyboard = nullptr; +} + +void SeatInfo::keymap(uint32_t format, int fd, size_t size) +{ + clear(); + + xkb_state_unref(_xkb_state); + _xkb_state = nullptr; + + if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) { + close(fd); + return; + } + + void *map_shm = mmap(nullptr, size, PROT_READ, MAP_PRIVATE, fd, 0); + close(fd); + if (map_shm == MAP_FAILED) + return; + + xkb_keymap *keymap = xkb_keymap_new_from_string( + xkb_context, + static_cast(map_shm), + XKB_KEYMAP_FORMAT_TEXT_V1, + XKB_KEYMAP_COMPILE_NO_FLAGS); + munmap(map_shm, size); + + if (keymap) { + _xkb_state = xkb_state_new(keymap); + xkb_keymap_unref(keymap); + } +} + +void SeatInfo::key(uint32_t key, uint32_t state) +{ + if (!_xkb_state) + return; + + xkb_keycode_t code = key + 8; + xkb_keysym_t sym = xkb_state_key_get_one_sym(_xkb_state, code); + if (sym == XKB_KEY_NoSymbol) + return; + + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + _pressed_syms.push_back(sym); + } else if (state == WL_KEYBOARD_KEY_STATE_RELEASED) { + auto it = std::find( + _pressed_syms.begin(), + _pressed_syms.end(), + sym); + if (it != _pressed_syms.end()) + _pressed_syms.erase(it); + } +} + +void SeatInfo::modifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) +{ + if (!_xkb_state) + return; + + xkb_state_update_mask(_xkb_state, depressed, latched, locked, 0, 0, group); } -void update_wl_queue() +void SeatInfo::clear() { - wl_display_dispatch_queue_pending(wl_display_ptr, queue); + _pressed_syms.clear(); } -void init_wayland_data() +void init_wayland_data(wl_display *display) { - if (!wl_display_ptr) - return; + if (wl_display_ptr || !display) + return; + + xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if (!xkb_context) + return; + + auto display_wrapped = static_cast(wl_proxy_create_wrapper(display)); + if (!display_wrapped) { + xkb_context_unref(xkb_context); + return; + } + + wl_queue_ptr = wl_display_create_queue(display); + if (!wl_queue_ptr) { + wl_proxy_wrapper_destroy(display_wrapped); + xkb_context_unref(xkb_context); + return; + } + + wl_proxy_set_queue(reinterpret_cast(display_wrapped), wl_queue_ptr); + + wl_registry_ptr = wl_display_get_registry(display_wrapped); + wl_proxy_wrapper_destroy(display_wrapped); - queue = wl_display_create_queue(wl_display_ptr); - struct wl_display *display_wrapped = (struct wl_display*)wl_proxy_create_wrapper(wl_display_ptr); - wl_proxy_set_queue((struct wl_proxy*)display_wrapped, queue); - wl_registry *registry = wl_display_get_registry(display_wrapped); - wl_proxy_wrapper_destroy(display_wrapped); - wl_registry_add_listener(registry, ®istry_listener, NULL); - wl_display_roundtrip_queue(wl_display_ptr, queue); - wl_display_roundtrip_queue(wl_display_ptr, queue); + if (!wl_registry_ptr) { + wl_event_queue_destroy(wl_queue_ptr); + xkb_context_unref(xkb_context); + return; + } + + wl_registry_add_listener(wl_registry_ptr, ®istry_listener, nullptr); + wl_display_ptr = display; +} + +void fini_wayland_data() +{ + if (!wl_display_ptr) + return; + + seats.clear(); + wl_registry_destroy(wl_registry_ptr); + wl_event_queue_destroy(wl_queue_ptr); + xkb_context_unref(xkb_context); + + wl_display_ptr = nullptr; +} + +bool any_wayland_seat_syms_are_pressed(const std::vector &syms) +{ + if (!wl_display_ptr) { + return false; + } + wl_display_dispatch_queue_pending(wl_display_ptr, wl_queue_ptr); + return std::any_of(seats.begin(), seats.end(), [syms](const std::unique_ptr &s) { + return s->are_pressed(syms); + }); }