@@ -160,10 +160,12 @@ constexpr ImGuiKey s_keyTable[] = {
160
160
};
161
161
162
162
static std::function<void ()> s_redraw;
163
+ static std::function<void (float )> s_scaleChanged;
163
164
static RunQueue* s_mainThreadTasks;
164
165
165
166
static struct wl_display * s_dpy;
166
167
static struct wl_compositor * s_comp;
168
+ static uint32_t s_comp_version;
167
169
static struct wl_surface * s_surf;
168
170
static struct wl_egl_window * s_eglWin;
169
171
static struct wl_shm * s_shm;
@@ -194,6 +196,7 @@ struct Output
194
196
{
195
197
int32_t scale;
196
198
wl_output* obj;
199
+ bool entered;
197
200
};
198
201
static std::unordered_map<uint32_t , std::unique_ptr<Output>> s_output;
199
202
static int s_maxScale = 1 ;
@@ -207,6 +210,19 @@ static uint64_t s_time;
207
210
static wl_fixed_t s_wheelAxisX, s_wheelAxisY;
208
211
static bool s_wheel;
209
212
213
+ static void RecomputeScale ()
214
+ {
215
+ // On wl_compositor >= 6 the scale is sent explicitly via wl_surface.preferred_buffer_scale.
216
+ if ( s_comp_version >= 6 ) return ;
217
+
218
+ int max = 1 ;
219
+ for ( auto & out : s_output )
220
+ {
221
+ if ( out.second ->entered && out.second ->scale > max ) max = out.second ->scale ;
222
+ }
223
+ s_maxScale = max;
224
+ }
225
+
210
226
static void PointerEnter ( void *, struct wl_pointer * pointer, uint32_t serial, struct wl_surface * surf, wl_fixed_t sx, wl_fixed_t sy )
211
227
{
212
228
wl_pointer_set_cursor ( pointer, serial, s_cursorSurf, s_cursorX, s_cursorY );
@@ -471,12 +487,7 @@ static void OutputMode( void*, struct wl_output* output, uint32_t flags, int32_t
471
487
472
488
static void OutputDone ( void *, struct wl_output * output )
473
489
{
474
- int max = 1 ;
475
- for ( auto & out : s_output )
476
- {
477
- if ( out.second ->scale > max ) max = out.second ->scale ;
478
- }
479
- s_maxScale = max;
490
+ RecomputeScale ();
480
491
}
481
492
482
493
static void OutputScale ( void * data, struct wl_output * output, int32_t scale )
@@ -506,7 +517,8 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const
506
517
{
507
518
if ( strcmp ( interface, wl_compositor_interface.name ) == 0 )
508
519
{
509
- s_comp = (wl_compositor*)wl_registry_bind ( reg, name, &wl_compositor_interface, 4 );
520
+ s_comp_version = version;
521
+ s_comp = (wl_compositor*)wl_registry_bind ( reg, name, &wl_compositor_interface, version >= 6 ? 6 : 4 );
510
522
}
511
523
else if ( strcmp ( interface, wl_shm_interface.name ) == 0 )
512
524
{
@@ -529,7 +541,7 @@ static void RegistryGlobal( void*, struct wl_registry* reg, uint32_t name, const
529
541
else if ( strcmp ( interface, wl_output_interface.name ) == 0 )
530
542
{
531
543
auto output = (wl_output*)wl_registry_bind ( reg, name, &wl_output_interface, 2 );
532
- auto ptr = std::make_unique<Output>( Output { 1 , output } );
544
+ auto ptr = std::make_unique<Output>( Output { 1 , output, false } );
533
545
wl_output_add_listener ( output, &outputListener, ptr.get () );
534
546
s_output.emplace ( name, std::move ( ptr ) );
535
547
}
@@ -545,6 +557,7 @@ static void RegistryGlobalRemove( void*, struct wl_registry* reg, uint32_t name
545
557
if ( it == s_output.end () ) return ;
546
558
wl_output_destroy ( it->second ->obj );
547
559
s_output.erase ( it );
560
+ RecomputeScale ();
548
561
}
549
562
550
563
constexpr struct wl_registry_listener registryListener = {
@@ -603,6 +616,43 @@ constexpr struct xdg_toplevel_listener toplevelListener = {
603
616
.close = XdgToplevelClose
604
617
};
605
618
619
+ static void SurfaceEnter ( void *, struct wl_surface * surface, struct wl_output * output )
620
+ {
621
+ for ( auto & out : s_output )
622
+ {
623
+ if ( out.second ->obj == output )
624
+ {
625
+ out.second ->entered = true ;
626
+ RecomputeScale ();
627
+ break ;
628
+ }
629
+ }
630
+ }
631
+
632
+ static void SurfaceLeave ( void *, struct wl_surface * surface, struct wl_output * output )
633
+ {
634
+ for ( auto & out : s_output )
635
+ {
636
+ if ( out.second ->obj == output )
637
+ {
638
+ out.second ->entered = false ;
639
+ RecomputeScale ();
640
+ break ;
641
+ }
642
+ }
643
+ }
644
+
645
+ static void SurfacePreferredBufferScale ( void *, struct wl_surface * surface, int32_t scale )
646
+ {
647
+ s_maxScale = scale;
648
+ }
649
+
650
+ constexpr struct wl_surface_listener surfaceListener = {
651
+ .enter = SurfaceEnter,
652
+ .leave = SurfaceLeave,
653
+ .preferred_buffer_scale = SurfacePreferredBufferScale,
654
+ };
655
+
606
656
static void SetupCursor ()
607
657
{
608
658
auto env_xcursor_theme = getenv ( " XCURSOR_THEME" );
@@ -624,9 +674,10 @@ static void SetupCursor()
624
674
s_cursorY = cursor->images [0 ]->hotspot_y / s_maxScale;
625
675
}
626
676
627
- Backend::Backend ( const char * title, const std::function<void ()>& redraw, RunQueue* mainThreadTasks )
677
+ Backend::Backend ( const char * title, const std::function<void ()>& redraw, const std::function<void( float )>& scaleChanged, RunQueue* mainThreadTasks )
628
678
{
629
679
s_redraw = redraw;
680
+ s_scaleChanged = scaleChanged;
630
681
s_mainThreadTasks = mainThreadTasks;
631
682
s_w = m_winPos.w ;
632
683
s_h = m_winPos.h ;
@@ -645,6 +696,7 @@ Backend::Backend( const char* title, const std::function<void()>& redraw, RunQue
645
696
if ( !s_seat ) { fprintf ( stderr, " No wayland seat!\n " ); exit ( 1 ); }
646
697
647
698
s_surf = wl_compositor_create_surface ( s_comp );
699
+ wl_surface_add_listener ( s_surf, &surfaceListener, nullptr );
648
700
s_eglWin = wl_egl_window_create ( s_surf, m_winPos.w , m_winPos.h );
649
701
s_xdgSurf = xdg_wm_base_get_xdg_surface ( s_wm, s_surf );
650
702
xdg_surface_add_listener ( s_xdgSurf, &xdgSurfaceListener, nullptr );
@@ -781,6 +833,7 @@ void Backend::NewFrame( int& w, int& h )
781
833
{
782
834
if ( s_prevScale != s_maxScale )
783
835
{
836
+ s_scaleChanged ( s_maxScale );
784
837
SetupCursor ();
785
838
wl_surface_set_buffer_scale ( s_surf, s_maxScale );
786
839
s_prevScale = s_maxScale;
0 commit comments