@@ -70,32 +70,78 @@ struct ThemeState {
7070 preference : ThemeMode ,
7171 resolved : ThemeMode ,
7272 last_applied : Option < ThemeMode > ,
73- last_checked : Instant ,
73+ last_checked : Option < Instant > ,
74+ detection_in_flight : bool ,
75+ detection_generation : u64 ,
76+ detection_sender : mpsc:: Sender < ( u64 , Option < ThemeMode > ) > ,
77+ detection_receiver : mpsc:: Receiver < ( u64 , Option < ThemeMode > ) > ,
7478}
7579
7680impl ThemeState {
7781 fn new ( preference : ThemeMode ) -> Self {
82+ let ( detection_sender, detection_receiver) = mpsc:: channel ( ) ;
7883 Self {
7984 resolved : crate :: ui:: theme:: resolve_theme_mode ( preference) ,
8085 last_applied : None ,
81- last_checked : Instant :: now ( ) ,
86+ last_checked : Some ( Instant :: now ( ) ) ,
87+ detection_in_flight : false ,
88+ detection_generation : 0 ,
89+ detection_sender,
90+ detection_receiver,
8291 preference,
8392 }
8493 }
8594
86- /// Polls the OS for system theme changes (throttled to every 2s) and
87- /// applies the theme if it changed. Returns `true` if the theme was applied.
95+ fn drain_detection_results ( & mut self ) {
96+ while let Ok ( ( generation, detected) ) = self . detection_receiver . try_recv ( ) {
97+ if generation != self . detection_generation {
98+ continue ;
99+ }
100+
101+ self . detection_in_flight = false ;
102+ if self . preference != ThemeMode :: System {
103+ continue ;
104+ }
105+ if let Some ( detected) = detected
106+ && detected != self . resolved
107+ {
108+ self . resolved = detected;
109+ }
110+ }
111+ }
112+
113+ fn request_system_detection ( & mut self , ctx : & egui:: Context , now : Instant ) {
114+ if self . detection_in_flight {
115+ return ;
116+ }
117+ if self
118+ . last_checked
119+ . is_some_and ( |last_checked| now. duration_since ( last_checked) < Duration :: from_secs ( 2 ) )
120+ {
121+ return ;
122+ }
123+
124+ self . last_checked = Some ( now) ;
125+ self . detection_in_flight = true ;
126+ let sender = self . detection_sender . clone ( ) ;
127+ let generation = self . detection_generation ;
128+ let ctx = ctx. clone ( ) ;
129+ tokio:: task:: spawn_blocking ( move || {
130+ let detected = crate :: ui:: theme:: try_detect_system_theme ( ) ;
131+ if sender. send ( ( generation, detected) ) . is_err ( ) {
132+ tracing:: debug!( "Dropping OS theme detection result because receiver closed" ) ;
133+ }
134+ ctx. request_repaint ( ) ;
135+ } ) ;
136+ }
137+
138+ /// Polls asynchronously for OS theme changes (throttled to every 2s) and
139+ /// applies the latest detected theme if it changed. Returns `true` if the
140+ /// theme was applied.
88141 fn poll_and_apply ( & mut self , ctx : & egui:: Context ) -> bool {
142+ self . drain_detection_results ( ) ;
89143 if self . preference == ThemeMode :: System {
90- let now = Instant :: now ( ) ;
91- if now. duration_since ( self . last_checked ) >= Duration :: from_secs ( 2 ) {
92- self . last_checked = now;
93- if let Some ( detected) = crate :: ui:: theme:: try_detect_system_theme ( )
94- && detected != self . resolved
95- {
96- self . resolved = detected;
97- }
98- }
144+ self . request_system_detection ( ctx, Instant :: now ( ) ) ;
99145 }
100146 if self . last_applied != Some ( self . resolved ) {
101147 crate :: ui:: theme:: apply_theme ( ctx, self . resolved ) ;
@@ -108,6 +154,9 @@ impl ThemeState {
108154
109155 fn apply_new_preference ( & mut self , ctx : & egui:: Context , new_theme : ThemeMode ) -> bool {
110156 self . preference = new_theme;
157+ self . detection_generation = self . detection_generation . wrapping_add ( 1 ) ;
158+ self . detection_in_flight = false ;
159+ let now = Instant :: now ( ) ;
111160 let mut detection_failed = false ;
112161 self . resolved = if new_theme == ThemeMode :: System {
113162 match crate :: ui:: theme:: try_detect_system_theme ( ) {
@@ -120,7 +169,7 @@ impl ThemeState {
120169 } else {
121170 new_theme
122171 } ;
123- self . last_checked = Instant :: now ( ) ;
172+ self . last_checked = Some ( now ) ;
124173 crate :: ui:: theme:: apply_theme ( ctx, self . resolved ) ;
125174 self . last_applied = Some ( self . resolved ) ;
126175 detection_failed
0 commit comments