@@ -25,6 +25,7 @@ use cosmic::{
25
25
Command , Element , Theme ,
26
26
} ;
27
27
use timedate_zbus:: TimeDateProxy ;
28
+ use tokio:: { sync:: watch, time} ;
28
29
29
30
use icu:: {
30
31
calendar:: DateTime ,
@@ -56,6 +57,8 @@ pub struct Window {
56
57
rectangle : Rectangle ,
57
58
token_tx : Option < calloop:: channel:: Sender < TokenRequest > > ,
58
59
config : TimeAppletConfig ,
60
+ show_seconds_rx : watch:: Receiver < bool > ,
61
+ show_seconds_tx : watch:: Sender < bool > ,
59
62
locale : Locale ,
60
63
}
61
64
@@ -136,6 +139,9 @@ impl cosmic::Application for Window {
136
139
// timezone is ever externally changed
137
140
let now: chrono:: DateTime < chrono:: FixedOffset > = chrono:: Local :: now ( ) . fixed_offset ( ) ;
138
141
142
+ // Synch `show_seconds` from the config within the time subscription
143
+ let ( show_seconds_tx, show_seconds_rx) = watch:: channel ( false ) ;
144
+
139
145
(
140
146
Self {
141
147
core,
@@ -147,6 +153,8 @@ impl cosmic::Application for Window {
147
153
rectangle : Rectangle :: default ( ) ,
148
154
token_tx : None ,
149
155
config : TimeAppletConfig :: default ( ) ,
156
+ show_seconds_tx,
157
+ show_seconds_rx,
150
158
locale,
151
159
} ,
152
160
Command :: none ( ) ,
@@ -166,16 +174,53 @@ impl cosmic::Application for Window {
166
174
}
167
175
168
176
fn subscription ( & self ) -> Subscription < Message > {
169
- fn time_subscription ( ) -> Subscription < ( ) > {
170
- subscription:: unfold ( "time-sub" , ( ) , move |( ) | async move {
171
- let now = chrono:: Local :: now ( ) ;
172
- let update_delay = chrono:: TimeDelta :: minutes ( 1 ) ;
173
-
174
- let duration = ( ( now + update_delay) . duration_trunc ( update_delay) . unwrap ( ) - now)
175
- . to_std ( )
176
- . unwrap ( ) ;
177
- tokio:: time:: sleep ( duration) . await ;
178
- ( ( ) , ( ) )
177
+ fn time_subscription ( mut show_seconds : watch:: Receiver < bool > ) -> Subscription < ( ) > {
178
+ subscription:: channel ( "time-sub" , 1 , |mut output| async move {
179
+ let mut period = if * show_seconds. borrow_and_update ( ) {
180
+ 1
181
+ } else {
182
+ 60
183
+ } ;
184
+ let mut timer = time:: interval ( time:: Duration :: from_secs ( period) ) ;
185
+ timer. set_missed_tick_behavior ( time:: MissedTickBehavior :: Skip ) ;
186
+
187
+ loop {
188
+ tokio:: select! {
189
+ _ = timer. tick( ) => {
190
+ #[ cfg( debug_assertions) ]
191
+ if let Err ( err) = output. send( ( ) ) . await {
192
+ tracing:: error!( ?err, "Failed sending tick request to applet" ) ;
193
+ }
194
+ #[ cfg( not( debug_assertions) ) ]
195
+ let _ = output. send( ( ) ) . await ;
196
+
197
+ // Calculate a delta if we're ticking per minute to keep ticks stable
198
+ // Based on i3status-rust
199
+ let current = chrono:: Local :: now( ) . second( ) as u64 % period;
200
+ if current != 0 {
201
+ timer. reset_after( time:: Duration :: from_secs( period - current) ) ;
202
+ }
203
+ } ,
204
+ // Update timer if the user toggles show_seconds
205
+ Ok ( ( ) ) = show_seconds. changed( ) => {
206
+ let seconds = * show_seconds. borrow_and_update( ) ;
207
+ if seconds {
208
+ period = 1 ;
209
+ timer = time:: interval( time:: Duration :: from_secs( period) ) ;
210
+ } else {
211
+ period = 60 ;
212
+ let delta = time:: Duration :: from_secs( period - chrono:: Local :: now( ) . second( ) as u64 % period) ;
213
+ let now = time:: Instant :: now( ) ;
214
+ // Start ticking from the next minute to update the time properly
215
+ let start = now + delta;
216
+ let period = time:: Duration :: from_secs( period) ;
217
+ timer = time:: interval_at( start, period) ;
218
+ }
219
+
220
+ timer. set_missed_tick_behavior( time:: MissedTickBehavior :: Skip ) ;
221
+ }
222
+ }
223
+ }
179
224
} )
180
225
}
181
226
@@ -221,7 +266,7 @@ impl cosmic::Application for Window {
221
266
222
267
Subscription :: batch ( vec ! [
223
268
rectangle_tracker_subscription( 0 ) . map( |e| Message :: Rectangle ( e. 1 ) ) ,
224
- time_subscription( ) . map( |_| Message :: Tick ) ,
269
+ time_subscription( self . show_seconds_rx . clone ( ) ) . map( |_| Message :: Tick ) ,
225
270
activation_token_subscription( 0 ) . map( Message :: Token ) ,
226
271
timezone_subscription( ) ,
227
272
self . core. watch_config( Self :: APP_ID ) . map( |u| {
@@ -356,6 +401,14 @@ impl cosmic::Application for Window {
356
401
Command :: none ( )
357
402
}
358
403
Message :: ConfigChanged ( c) => {
404
+ self . show_seconds_tx . send_if_modified ( |show_seconds| {
405
+ if * show_seconds == c. show_seconds {
406
+ false
407
+ } else {
408
+ * show_seconds = c. show_seconds ;
409
+ true
410
+ }
411
+ } ) ;
359
412
self . config = c;
360
413
Command :: none ( )
361
414
}
@@ -396,6 +449,10 @@ impl cosmic::Application for Window {
396
449
397
450
time_bag. hour = Some ( components:: Numeric :: Numeric ) ;
398
451
time_bag. minute = Some ( components:: Numeric :: Numeric ) ;
452
+ time_bag. second = self
453
+ . config
454
+ . show_seconds
455
+ . then_some ( components:: Numeric :: Numeric ) ;
399
456
400
457
let hour_cycle = if self . config . military_time {
401
458
preferences:: HourCycle :: H23
0 commit comments