wayland: Keep track of entered outputs for scale

Wayland kindly informs us which outputs the surface is on, to be used
for scale computation (at least on wl_compositor < 6). On mixed DPI
setups this fixes Tracy potentially using a higher scale than the output
it's displayed on.

However, as is, this commit results in Tracy always using scale 1,
because at the point of backend creation (which is when the scale is
queried) the surface is not yet displayed on any outputs, so a scale of
1 is assumed.
This commit is contained in:
Ivan Molodetskikh 2024-01-24 12:19:52 +04:00
parent c4863d4324
commit bf3bd28bfa

View File

@ -194,6 +194,7 @@ struct Output
{
int32_t scale;
wl_output* obj;
bool entered;
};
static std::unordered_map<uint32_t, std::unique_ptr<Output>> s_output;
static int s_maxScale = 1;
@ -207,6 +208,16 @@ static uint64_t s_time;
static wl_fixed_t s_wheelAxisX, s_wheelAxisY;
static bool s_wheel;
static void RecomputeScale()
{
int max = 1;
for( auto& out : s_output )
{
if( out.second->entered && out.second->scale > max ) max = out.second->scale;
}
s_maxScale = max;
}
static void PointerEnter( void*, struct wl_pointer* pointer, uint32_t serial, struct wl_surface* surf, wl_fixed_t sx, wl_fixed_t sy )
{
wl_pointer_set_cursor( pointer, serial, s_cursorSurf, s_cursorX, s_cursorY );
@ -471,12 +482,7 @@ static void OutputMode( void*, struct wl_output* output, uint32_t flags, int32_t
static void OutputDone( void*, struct wl_output* output )
{
int max = 1;
for( auto& out : s_output )
{
if( out.second->scale > max ) max = out.second->scale;
}
s_maxScale = max;
RecomputeScale();
}
static void OutputScale( void* data, struct wl_output* output, int32_t scale )
@ -529,7 +535,7 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const
else if( strcmp( interface, wl_output_interface.name ) == 0 )
{
auto output = (wl_output*)wl_registry_bind( reg, name, &wl_output_interface, 2 );
auto ptr = std::make_unique<Output>( Output { 1, output } );
auto ptr = std::make_unique<Output>( Output { 1, output, false } );
wl_output_add_listener( output, &outputListener, ptr.get() );
s_output.emplace( name, std::move( ptr ) );
}
@ -545,6 +551,7 @@ static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name
if( it == s_output.end() ) return;
wl_output_destroy( it->second->obj );
s_output.erase( it );
RecomputeScale();
}
constexpr struct wl_registry_listener registryListener = {
@ -603,6 +610,37 @@ constexpr struct xdg_toplevel_listener toplevelListener = {
.close = XdgToplevelClose
};
static void SurfaceEnter( void*, struct wl_surface* surface, struct wl_output* output )
{
for ( auto& out : s_output )
{
if ( out.second->obj == output )
{
out.second->entered = true;
RecomputeScale();
break;
}
}
}
static void SurfaceLeave( void*, struct wl_surface* surface, struct wl_output* output )
{
for ( auto& out : s_output )
{
if ( out.second->obj == output )
{
out.second->entered = false;
RecomputeScale();
break;
}
}
}
constexpr struct wl_surface_listener surfaceListener = {
.enter = SurfaceEnter,
.leave = SurfaceLeave,
};
static void SetupCursor()
{
auto env_xcursor_theme = getenv( "XCURSOR_THEME" );
@ -645,6 +683,7 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, RunQue
if( !s_seat ) { fprintf( stderr, "No wayland seat!\n" ); exit( 1 ); }
s_surf = wl_compositor_create_surface( s_comp );
wl_surface_add_listener( s_surf, &surfaceListener, nullptr );
s_eglWin = wl_egl_window_create( s_surf, m_winPos.w, m_winPos.h );
s_xdgSurf = xdg_wm_base_get_xdg_surface( s_wm, s_surf );
xdg_surface_add_listener( s_xdgSurf, &xdgSurfaceListener, nullptr );