From 367ed695018c1988307e267851f2d173443c1bbb Mon Sep 17 00:00:00 2001 From: Bartosz Taudul Date: Wed, 12 Feb 2025 00:21:27 +0100 Subject: [PATCH] Use XDG toplevel icon protocol to set the icon. --- profiler/CMakeLists.txt | 4 ++ profiler/src/BackendWayland.cpp | 80 +++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/profiler/CMakeLists.txt b/profiler/CMakeLists.txt index dbb87284..8a148d1b 100644 --- a/profiler/CMakeLists.txt +++ b/profiler/CMakeLists.txt @@ -148,6 +148,10 @@ if(USE_WAYLAND) PROTOCOL ${wayland-protocols_SOURCE_DIR}/unstable/tablet/tablet-unstable-v2.xml BASENAME tablet ) + ecm_add_wayland_client_protocol(PROFILER_FILES + PROTOCOL ${wayland-protocols_SOURCE_DIR}/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml + BASENAME xdg-toplevel-icon + ) elseif(EMSCRIPTEN) set(PROFILER_FILES ${PROFILER_FILES} src/BackendEmscripten.cpp diff --git a/profiler/src/BackendWayland.cpp b/profiler/src/BackendWayland.cpp index 0bf6d1b9..3d5df3fd 100644 --- a/profiler/src/BackendWayland.cpp +++ b/profiler/src/BackendWayland.cpp @@ -25,8 +25,10 @@ #include "wayland-fractional-scale-client-protocol.h" #include "wayland-viewporter-client-protocol.h" #include "wayland-cursor-shape-client-protocol.h" +#include "wayland-xdg-toplevel-icon-client-protocol.h" #include "profiler/TracyImGui.hpp" +#include "stb_image_resize.h" #include "Backend.hpp" #include "RunQueue.hpp" @@ -213,6 +215,8 @@ static std::string s_clipboard, s_clipboardIncoming; static struct wl_data_offer* s_dataOffer; static struct wl_data_offer* s_newDataOffer; static bool s_newDataOfferValid; +static struct xdg_toplevel_icon_manager_v1* s_iconMgr; +static std::vector s_iconSizes; struct Output { @@ -566,6 +570,21 @@ constexpr struct zxdg_toplevel_decoration_v1_listener decorationListener = { }; +static void IconMgrSize( void*, struct xdg_toplevel_icon_manager_v1*, int32_t size ) +{ + s_iconSizes.push_back( size ); +} + +static void IconMgrDone( void*, struct xdg_toplevel_icon_manager_v1* ) +{ +} + +constexpr struct xdg_toplevel_icon_manager_v1_listener iconMgrListener = { + .icon_size = IconMgrSize, + .done = IconMgrDone +}; + + static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const char* interface, uint32_t version ) { if( strcmp( interface, wl_compositor_interface.name ) == 0 ) @@ -619,6 +638,11 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const { s_dataDevMgr = (wl_data_device_manager*)wl_registry_bind( reg, name, &wl_data_device_manager_interface, 2 ); } + else if( strcmp( interface, xdg_toplevel_icon_manager_v1_interface.name ) == 0 ) + { + s_iconMgr = (xdg_toplevel_icon_manager_v1*)wl_registry_bind( reg, name, &xdg_toplevel_icon_manager_v1_interface, 1 ); + xdg_toplevel_icon_manager_v1_add_listener( s_iconMgr, &iconMgrListener, nullptr ); + } } static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name ) @@ -1017,6 +1041,7 @@ Backend::~Backend() { ImGui_ImplOpenGL3_Shutdown(); + if( s_iconMgr ) xdg_toplevel_icon_manager_v1_destroy( s_iconMgr ); if( s_dataOffer ) wl_data_offer_destroy( s_dataOffer ); if( s_dataSource ) wl_data_source_destroy( s_dataSource ); if( s_dataDev ) wl_data_device_destroy( s_dataDev ); @@ -1215,6 +1240,61 @@ void Backend::EndFrame() void Backend::SetIcon( uint8_t* data, int w, int h ) { + if( !s_iconMgr ) return; + if( s_iconSizes.empty() ) return; + + size_t size = 0; + for( auto sz : s_iconSizes ) + { + size += sz * sz; + } + size *= 4; + + auto path = getenv( "XDG_RUNTIME_DIR" ); + if( !path ) return; + + std::string shmPath = path; + shmPath += "/tracy_icon-XXXXXX"; + int fd = mkstemp( shmPath.data() ); + if( fd < 0 ) return; + unlink( shmPath.data() ); + ftruncate( fd, size ); + auto membuf = (char*)mmap( nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 ); + if( membuf == MAP_FAILED ) + { + close( fd ); + return; + } + + auto pool = wl_shm_create_pool( s_shm, fd, size ); + close( fd ); + auto icon = xdg_toplevel_icon_manager_v1_create_icon( s_iconMgr ); + + auto rgb = new uint32_t[w * h]; + auto bgr = (uint32_t*)data; + for( int i=0; i> 16 ) & 0xff ); + } + + std::vector bufs; + int32_t offset = 0; + for( auto sz : s_iconSizes ) + { + auto buffer = wl_shm_pool_create_buffer( pool, offset, sz, sz, sz * 4, WL_SHM_FORMAT_ARGB8888 ); + bufs.push_back( buffer ); + + auto ptr = membuf + offset; + offset += sz * sz * 4; + + stbir_resize_uint8( (uint8_t*)rgb, w, h, 0, (uint8_t*)ptr, sz, sz, 0, 4 ); + xdg_toplevel_icon_v1_add_buffer( icon, buffer, sz ); + } + + xdg_toplevel_icon_manager_v1_set_icon( s_iconMgr, s_toplevel, icon ); + xdg_toplevel_icon_v1_destroy( icon ); + for( auto buf : bufs ) wl_buffer_destroy( buf ); + wl_shm_pool_destroy( pool ); } void Backend::SetTitle( const char* title )