From 2cfa28b1075166aac597eb6e7722b667be4e2da9 Mon Sep 17 00:00:00 2001 From: Adam Date: Tue, 13 May 2025 19:34:44 +0100 Subject: [PATCH] library: use SDL_FlashWindow instead of xcb props --- src/library/so/main.c | 95 +++++++++++-------------------------------- src/library/so/sdl.h | 10 +++++ 2 files changed, 34 insertions(+), 71 deletions(-) diff --git a/src/library/so/main.c b/src/library/so/main.c index ac58335..262ac9f 100644 --- a/src/library/so/main.c +++ b/src/library/so/main.c @@ -42,6 +42,8 @@ static xcb_window_t main_window_xcb = 0; static uint32_t main_window_width = 0; static uint32_t main_window_height = 0; +static void* main_window_sdl = NULL; + static uint8_t mousein_real = 0; static uint8_t mousein_fake = 0; @@ -73,24 +75,19 @@ static unsigned int (*real_eglTerminate)(void*) = NULL; static xcb_generic_event_t* (*real_xcb_poll_for_event)(xcb_connection_t*) = NULL; static xcb_generic_event_t* (*real_xcb_poll_for_queued_event)(xcb_connection_t*) = NULL; static xcb_generic_event_t* (*real_xcb_wait_for_event)(xcb_connection_t*) = NULL; -static xcb_void_cookie_t (*real_xcb_get_property)(xcb_connection_t*, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint32_t, uint32_t) = NULL; -static xcb_get_property_reply_t* (*real_xcb_get_property_reply)(xcb_connection_t*, xcb_void_cookie_t, xcb_generic_event_t**) = NULL; -static int (*real_xcb_get_property_value_length)(const xcb_get_property_reply_t*) = NULL; -static void* (*real_xcb_get_property_value)(const xcb_get_property_reply_t*) = NULL; -static xcb_void_cookie_t (*real_xcb_change_property)(xcb_connection_t*, uint8_t, xcb_window_t, xcb_atom_t, xcb_atom_t, uint8_t, uint32_t, const void*) = NULL; -static xcb_void_cookie_t (*real_xcb_change_window_attributes)(xcb_connection_t*, xcb_window_t, uint32_t, const uint32_t*) = NULL; static int (*real_xcb_flush)(xcb_connection_t*) = NULL; +static void* (*real_SDL_CreateWindow)(const char*, int, int, SDL_WindowFlags) = NULL; static void* (*real_SDL_CreateSystemCursor)(SDL_SystemCursor) = NULL; static unsigned char (*real_SDL_SetCursor)(void*) = NULL; +static bool (*real_SDL_FlashWindow)(void*, SDL_FlashOperation) = NULL; static struct GLLibFunctions libgl = {0}; static void* sdl_cursor = NULL; static void* sdl_system_cursor = NULL; static uint8_t cursor_change_pending = 0; -static uint8_t flash_change_pending = false; -static uint8_t pending_flash; +static uint8_t pending_flash = false; static pthread_mutex_t cursor_lock; static pthread_mutex_t focus_lock; @@ -255,28 +252,20 @@ static void _bolt_init_libxcb(unsigned long addr, const Elf32_Word* gnu_hash_tab if (sym) real_xcb_poll_for_queued_event = sym->st_value + libxcb_addr; sym = _bolt_lookup_symbol("xcb_wait_for_event", gnu_hash_table, hash_table, string_table, symbol_table); if (sym) real_xcb_wait_for_event = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_get_property", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_get_property = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_get_property_reply", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_get_property_reply = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_get_property_value_length", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_get_property_value_length = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_get_property_value", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_get_property_value = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_change_property", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_change_property = sym->st_value + libxcb_addr; - sym = _bolt_lookup_symbol("xcb_change_window_attributes", gnu_hash_table, hash_table, string_table, symbol_table); - if (sym) real_xcb_change_window_attributes = sym->st_value + libxcb_addr; sym = _bolt_lookup_symbol("xcb_flush", gnu_hash_table, hash_table, string_table, symbol_table); if (sym) real_xcb_flush = sym->st_value + libxcb_addr; } static void _bolt_init_libsdl(unsigned long addr, const Elf32_Word* gnu_hash_table, const ElfW(Word)* hash_table, const char* string_table, const ElfW(Sym)* symbol_table) { libsdl_addr = (void*)addr; - const ElfW(Sym)* sym = _bolt_lookup_symbol("SDL_SetCursor", gnu_hash_table, hash_table, string_table, symbol_table); + const ElfW(Sym)* sym = _bolt_lookup_symbol("SDL_CreateWindow", gnu_hash_table, hash_table, string_table, symbol_table); + if (sym) real_SDL_CreateWindow = sym->st_value + libsdl_addr; + sym = _bolt_lookup_symbol("SDL_SetCursor", gnu_hash_table, hash_table, string_table, symbol_table); if (sym) real_SDL_SetCursor = sym->st_value + libsdl_addr; sym = _bolt_lookup_symbol("SDL_CreateSystemCursor", gnu_hash_table, hash_table, string_table, symbol_table); if (sym) real_SDL_CreateSystemCursor = sym->st_value + libsdl_addr; + sym = _bolt_lookup_symbol("SDL_FlashWindow", gnu_hash_table, hash_table, string_table, symbol_table); + if (sym) real_SDL_FlashWindow = sym->st_value + libsdl_addr; } static int _bolt_dl_iterate_callback(struct dl_phdr_info* info, size_t size, void* args) { @@ -346,12 +335,7 @@ static void _bolt_init_functions() { } void _bolt_flash_window(void) { - pthread_mutex_lock(&focus_lock); - const uint8_t focus = window_focus; - pthread_mutex_unlock(&focus_lock); - if (focus) return; pthread_mutex_lock(&cursor_lock); - flash_change_pending = true; pending_flash = true; pthread_mutex_unlock(&cursor_lock); } @@ -706,10 +690,6 @@ static uint8_t _bolt_handle_xcb_event(xcb_connection_t* c, xcb_generic_event_t* pthread_mutex_lock(&focus_lock); window_focus = true; pthread_mutex_unlock(&focus_lock); - pthread_mutex_lock(&cursor_lock); - flash_change_pending = true; - pending_flash = false; - pthread_mutex_unlock(&cursor_lock); break; } case XCB_FOCUS_OUT: {// when the game window loses focus @@ -775,10 +755,12 @@ xcb_generic_event_t* xcb_wait_for_event(xcb_connection_t* c) { int xcb_flush(xcb_connection_t* c) { pthread_mutex_lock(&cursor_lock); - const uint8_t change_pending = flash_change_pending; - uint8_t do_flash = pending_flash; - flash_change_pending = false; + const uint8_t do_flash = pending_flash && main_window_sdl; + // call SDL_SetCursor if there's a pending request to do so. + // this is carefully built to make sure the mutex is released before calling any functions that + // might cause a re-entry and a double-lock on the mutex, while also making sure that it'll + // always be released, exactly once. switch (cursor_change_pending) { case 1: if (sdl_cursor) { @@ -802,44 +784,8 @@ int xcb_flush(xcb_connection_t* c) { pthread_mutex_unlock(&cursor_lock); } - if (change_pending) { - bool do_change = true; - if (do_flash) { - pthread_mutex_lock(&focus_lock); - const uint8_t focus = window_focus; - pthread_mutex_unlock(&focus_lock); - if (focus) c = false; - } - - if (do_change) { - XWMHints hints; - XWMHints* ptr_hints = NULL; - uint32_t hints_length_dwords = sizeof(XWMHints) >> 2; - const xcb_void_cookie_t cookie = real_xcb_get_property(c, false, main_window_xcb, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 0, hints_length_dwords); - xcb_get_property_reply_t* const reply = real_xcb_get_property_reply(c, cookie, NULL); - - if (reply) { - const int length = real_xcb_get_property_value_length(reply); - if (length > 0) { - hints_length_dwords = length; - ptr_hints = real_xcb_get_property_value(reply); - if (do_flash) { - ptr_hints->flags |= (1 << 8); - } else { - ptr_hints->flags &= ~(1 << 8); - } - } - } - - if (!ptr_hints) { - memset(&hints, 0, sizeof hints); - if (do_flash) hints.flags = (1 << 8); - ptr_hints = &hints; - } - - real_xcb_change_property(c, XCB_PROP_MODE_REPLACE, main_window_xcb, XCB_ATOM_WM_HINTS, XCB_ATOM_WM_HINTS, 32, hints_length_dwords, ptr_hints); - free(reply); - } + if (do_flash) { + real_SDL_FlashWindow(main_window_sdl, SDL_FLASH_UNTIL_FOCUSED); } return real_xcb_flush(c); @@ -855,6 +801,12 @@ unsigned char SDL_SetCursor(void* cursor) { return ret; } +void* SDL_CreateWindow(const char* window, int w, int h, SDL_WindowFlags flags) { + void* ret = real_SDL_CreateWindow(window, w, h, flags); + if (!main_window_sdl) main_window_sdl = ret; + return ret; +} + void* dlopen(const char*, int); void* dlsym(void*, const char*); void* dlvsym(void*, const char*, const char*); @@ -893,6 +845,7 @@ static void* _bolt_dl_lookup(void* handle, const char* symbol) { if (strcmp(symbol, "xcb_flush") == 0) return xcb_flush; } else if (handle == libsdl_addr) { if (strcmp(symbol, "SDL_SetCursor") == 0) return SDL_SetCursor; + if (strcmp(symbol, "SDL_CreateWindow") == 0) return SDL_CreateWindow; } return NULL; } diff --git a/src/library/so/sdl.h b/src/library/so/sdl.h index c5fdb14..50dd790 100644 --- a/src/library/so/sdl.h +++ b/src/library/so/sdl.h @@ -1,5 +1,7 @@ // stuff lifted from SDL headers +#include + typedef enum SDL_SystemCursor { SDL_SYSTEM_CURSOR_DEFAULT, /**< Default cursor. Usually an arrow. */ SDL_SYSTEM_CURSOR_TEXT, /**< Text selection. Usually an I-beam. */ @@ -23,3 +25,11 @@ typedef enum SDL_SystemCursor { SDL_SYSTEM_CURSOR_W_RESIZE, /**< Window resize left. May be EW_RESIZE. */ SDL_SYSTEM_CURSOR_COUNT } SDL_SystemCursor; + +typedef enum SDL_FlashOperation { + SDL_FLASH_CANCEL, /**< Cancel any window flash state */ + SDL_FLASH_BRIEFLY, /**< Flash the window briefly to get attention */ + SDL_FLASH_UNTIL_FOCUSED /**< Flash the window until it gets focus */ +} SDL_FlashOperation; + +typedef uint64_t SDL_WindowFlags;