Skip to content

Commit 7d989e3

Browse files
committed
use new display identifier OSDs timer logic and immediately close those OSDs when leaving the display page, closing the settings app gracefully or forcefully with super key + q
1 parent 1e43499 commit 7d989e3

File tree

1 file changed

+73
-55
lines changed
  • cosmic-settings/src/pages/display

1 file changed

+73
-55
lines changed

cosmic-settings/src/pages/display/mod.rs

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,19 @@ static DPI_SCALES: &[u32] = &[50, 75, 100, 125, 150, 175, 200, 225, 250, 275, 30
2828
static DPI_SCALE_LABELS: LazyLock<Vec<String>> =
2929
LazyLock::new(|| DPI_SCALES.iter().map(|scale| format!("{scale}%")).collect());
3030

31+
/// Guard that ensures display identifiers are dismissed when dropped
32+
/// This handles the case where the app is killed and async cleanup doesn't complete
33+
struct DisplayIdentifierGuard;
34+
35+
impl Drop for DisplayIdentifierGuard {
36+
fn drop(&mut self) {
37+
// Run synchronously to ensure it completes even if the process is being killed
38+
let _ = std::process::Command::new("cosmic-osd")
39+
.arg("dismiss-display-identifiers")
40+
.output();
41+
}
42+
}
43+
3144
/// Display color depth options
3245
#[allow(dead_code)]
3346
#[derive(Clone, Copy, Debug)]
@@ -138,6 +151,8 @@ pub struct Page {
138151
active_display: OutputKey,
139152
randr_handle: Option<(oneshot::Sender<()>, cosmic::iced::task::Handle)>,
140153
hotplug_handle: Option<(oneshot::Sender<()>, cosmic::iced::task::Handle)>,
154+
display_identifier_handle: Option<(oneshot::Sender<()>, ())>,
155+
display_identifier_guard: Option<DisplayIdentifierGuard>,
141156
config: Config,
142157
cache: ViewCache,
143158
// context: Option<ContextDrawer>,
@@ -163,6 +178,8 @@ impl Default for Page {
163178
active_display: OutputKey::default(),
164179
randr_handle: None,
165180
hotplug_handle: None,
181+
display_identifier_handle: None,
182+
display_identifier_guard: None,
166183
config: Config::default(),
167184
cache: ViewCache::default(),
168185
// context: None,
@@ -365,6 +382,56 @@ impl page::Page<crate::pages::Message> for Page {
365382
tasks.push(hotplug_task);
366383
self.hotplug_handle = Some((hotplug_cancel_tx, hotplug_handle));
367384

385+
// Start a periodic task to send identify displays message every 0.5 seconds
386+
// This resets the 1-second auto-close timer in cosmic-osd
387+
let (identifier_cancel_tx, identifier_cancel_rx) = oneshot::channel::<()>();
388+
let identifier_task =
389+
Task::stream(async_fn_stream::fn_stream(|_emitter| async move {
390+
let identifier_loop = async {
391+
loop {
392+
match tokio::process::Command::new("cosmic-osd")
393+
.arg("identify-displays")
394+
.output()
395+
.await
396+
{
397+
Ok(output) => {
398+
if !output.status.success() {
399+
tracing::error!(
400+
"cosmic-osd identify-displays failed: {}",
401+
String::from_utf8_lossy(&output.stderr)
402+
);
403+
}
404+
}
405+
Err(why) => {
406+
tracing::error!(
407+
why = why.to_string(),
408+
"failed to execute cosmic-osd identify-displays"
409+
);
410+
}
411+
}
412+
413+
tokio::time::sleep(Duration::from_millis(500)).await;
414+
}
415+
};
416+
417+
tokio::select! {
418+
_ = identifier_cancel_rx => {
419+
let _ = tokio::process::Command::new("cosmic-osd")
420+
.arg("dismiss-display-identifiers")
421+
.output()
422+
.await;
423+
}
424+
_ = identifier_loop => {
425+
// Loop will never complete, but this branch is needed for tokio::select
426+
}
427+
}
428+
}));
429+
430+
tasks.push(identifier_task);
431+
self.display_identifier_handle = Some((identifier_cancel_tx, ()));
432+
// Create guard that will dismiss identifiers immediately if the app is killed
433+
self.display_identifier_guard = Some(DisplayIdentifierGuard);
434+
368435
cosmic::task::batch(tasks)
369436
}
370437

@@ -379,29 +446,12 @@ impl page::Page<crate::pages::Message> for Page {
379446
handle.abort();
380447
}
381448

382-
// Dismiss display identifiers when leaving the page
383-
tokio::spawn(async {
384-
match tokio::process::Command::new("cosmic-osd")
385-
.arg("dismiss-display-identifiers")
386-
.output()
387-
.await
388-
{
389-
Ok(output) => {
390-
if !output.status.success() {
391-
tracing::error!(
392-
"cosmic-osd dismiss-display-identifiers failed: {}",
393-
String::from_utf8_lossy(&output.stderr)
394-
);
395-
}
396-
}
397-
Err(why) => {
398-
tracing::error!(
399-
why = why.to_string(),
400-
"failed to execute cosmic-osd dismiss-display-identifiers"
401-
);
402-
}
403-
}
404-
});
449+
if let Some((canceller, ())) = self.display_identifier_handle.take() {
450+
_ = canceller.send(());
451+
}
452+
453+
// Remove the guard so it doesn't dismiss again after the async task completes
454+
self.display_identifier_guard = None;
405455

406456
Task::none()
407457
}
@@ -641,38 +691,6 @@ impl Page {
641691
match Arc::into_inner(randr) {
642692
Some(Ok(outputs)) => {
643693
self.update_displays(outputs);
644-
645-
// Show display identifiers if there are 2+ enabled displays
646-
let enabled_count =
647-
self.list.outputs.values().filter(|o| o.enabled).count();
648-
649-
if enabled_count >= 2 {
650-
return Task::perform(
651-
async {
652-
match tokio::process::Command::new("cosmic-osd")
653-
.arg("identify-displays")
654-
.output()
655-
.await
656-
{
657-
Ok(output) => {
658-
if !output.status.success() {
659-
tracing::error!(
660-
"cosmic-osd identify-displays failed: {}",
661-
String::from_utf8_lossy(&output.stderr)
662-
);
663-
}
664-
}
665-
Err(why) => {
666-
tracing::error!(
667-
why = why.to_string(),
668-
"failed to execute cosmic-osd identify-displays"
669-
);
670-
}
671-
}
672-
},
673-
|_| app::Message::None,
674-
);
675-
}
676694
}
677695

678696
Some(Err(why)) => {

0 commit comments

Comments
 (0)