From fb4a2be86a0561651772080a98e5062383222bcd Mon Sep 17 00:00:00 2001 From: Kacper Paczos Date: Sat, 22 Aug 2026 22:20:54 +0200 Subject: [PATCH 1/3] feat: don't let a running box be deleted until it is stopped Delete Box removes the container with --force, so it would happily tear down a box that is still running and whatever is working inside it. Disable the Delete row while the box is up, with a subtitle pointing at the Stop button that is already on the header, and enable it again once the box is down. --- src/main.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/main.rs b/src/main.rs index a20908a..a8f2f2f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -423,6 +423,12 @@ fn load_boxes(scroll_area: >k::Box, window: &ApplicationWindow, active_page: O } } +/// Whether the Delete Box action should be offered. A running box has to be +/// stopped first, so deleting is only allowed once it is down. +fn delete_is_allowed(is_running: bool) -> bool { + !is_running +} + fn make_box_tab(dbox: &DBox, window: &ApplicationWindow, tab_num: u32) -> gtk::Box { let box_name = dbox.name.clone(); @@ -538,6 +544,15 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow, tab_num: u32) -> gtk::B let win_clone = window.clone(); delete_row.connect_activated(move |_row| on_delete_clicked(&win_clone, del_bn_clone.clone())); + // Deleting a running box would pull it out from under whatever is using it, + // so make the user stop it first. The Stop button on the header is right + // there while the box is up; once it is down the row enables itself. + if !delete_is_allowed(dbox.is_running) { + delete_row.set_sensitive(false); + // TRANSLATORS: Explains why Delete Box is greyed out on a running box + delete_row.set_subtitle(&gettext("Stop the box before deleting it")); + } + // Clone Box Icon let clone_icon = gtk::Image::from_icon_name(&get_available_icon_name(COPY_ICON_NAMES)); @@ -2081,3 +2096,18 @@ fn show_preferred_terminal_popup(window: &ApplicationWindow) { term_pref_popup.set_child(Some(&main_box)); term_pref_popup.present(); } + +#[cfg(test)] +mod delete_gate_tests { + use super::delete_is_allowed; + + #[test] + fn running_box_cannot_be_deleted() { + assert!(!delete_is_allowed(true)); + } + + #[test] + fn stopped_box_can_be_deleted() { + assert!(delete_is_allowed(false)); + } +} From 88785806289e3bc22c501bb58b61da4cf35cc708 Mon Sep 17 00:00:00 2001 From: Kacper Paczos Date: Sun, 23 Aug 2026 09:45:43 +0200 Subject: [PATCH 2/3] simplify: check the running state inline A one-line predicate and its tests said nothing the condition itself does not; the row is now gated directly on dbox.is_running. --- src/main.rs | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/main.rs b/src/main.rs index a8f2f2f..8b8695b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -423,12 +423,6 @@ fn load_boxes(scroll_area: >k::Box, window: &ApplicationWindow, active_page: O } } -/// Whether the Delete Box action should be offered. A running box has to be -/// stopped first, so deleting is only allowed once it is down. -fn delete_is_allowed(is_running: bool) -> bool { - !is_running -} - fn make_box_tab(dbox: &DBox, window: &ApplicationWindow, tab_num: u32) -> gtk::Box { let box_name = dbox.name.clone(); @@ -547,7 +541,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow, tab_num: u32) -> gtk::B // Deleting a running box would pull it out from under whatever is using it, // so make the user stop it first. The Stop button on the header is right // there while the box is up; once it is down the row enables itself. - if !delete_is_allowed(dbox.is_running) { + if dbox.is_running { delete_row.set_sensitive(false); // TRANSLATORS: Explains why Delete Box is greyed out on a running box delete_row.set_subtitle(&gettext("Stop the box before deleting it")); @@ -2096,18 +2090,3 @@ fn show_preferred_terminal_popup(window: &ApplicationWindow) { term_pref_popup.set_child(Some(&main_box)); term_pref_popup.present(); } - -#[cfg(test)] -mod delete_gate_tests { - use super::delete_is_allowed; - - #[test] - fn running_box_cannot_be_deleted() { - assert!(!delete_is_allowed(true)); - } - - #[test] - fn stopped_box_can_be_deleted() { - assert!(delete_is_allowed(false)); - } -} From 81865643167fc9594ccc7311640dfe98d5c33579 Mon Sep 17 00:00:00 2001 From: Kacper Paczos Date: Sun, 23 Aug 2026 21:50:19 +0200 Subject: [PATCH 3/3] feat: grey out Delete Box without a subtitle The note under the row made it taller only while the box was running, so the list shifted on Start and Stop; the greyed-out row is clear enough by itself. --- src/main.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main.rs b/src/main.rs index 8b8695b..e2ead9a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -541,11 +541,7 @@ fn make_box_tab(dbox: &DBox, window: &ApplicationWindow, tab_num: u32) -> gtk::B // Deleting a running box would pull it out from under whatever is using it, // so make the user stop it first. The Stop button on the header is right // there while the box is up; once it is down the row enables itself. - if dbox.is_running { - delete_row.set_sensitive(false); - // TRANSLATORS: Explains why Delete Box is greyed out on a running box - delete_row.set_subtitle(&gettext("Stop the box before deleting it")); - } + delete_row.set_sensitive(!dbox.is_running); // Clone Box Icon let clone_icon = gtk::Image::from_icon_name(&get_available_icon_name(COPY_ICON_NAMES));