Skip to content

Commit 556ede5

Browse files
committed
fix flatpak terminal list not updating
1 parent 011731f commit 556ede5

File tree

4 files changed

+106
-48
lines changed

4 files changed

+106
-48
lines changed

src/backends/supported_terminals.rs

Lines changed: 75 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,35 @@ use gtk::prelude::*;
99
use tracing::{error, info, warn};
1010

1111
use crate::fakers::{Command, CommandRunner, FdMode};
12+
use crate::query::Query;
1213

1314
use gtk::subclass::prelude::*;
1415

1516
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
1617
pub struct Terminal {
1718
pub name: String,
1819
pub program: String,
20+
/// Arguments that come after the program but before the separator_arg.
21+
/// For example, for flatpak terminals: ["run", "org.gnome.Console"]
22+
#[serde(default)]
23+
pub extra_args: Vec<String>,
1924
pub separator_arg: String,
2025
pub read_only: bool,
2126
}
2227

28+
impl Terminal {
29+
/// Returns a unique identifier for this terminal combining program and extra_args.
30+
/// This is used for deduplication since multiple terminals may use the same program
31+
/// (e.g., multiple flatpak terminals all use "flatpak" as the program).
32+
pub fn full_command_id(&self) -> String {
33+
if self.extra_args.is_empty() {
34+
self.program.clone()
35+
} else {
36+
format!("{} {}", self.program, self.extra_args.join(" "))
37+
}
38+
}
39+
}
40+
2341
static SUPPORTED_TERMINALS: LazyLock<Vec<Terminal>> = LazyLock::new(|| {
2442
[
2543
("GNOME Console", "kgx", "--"),
@@ -44,6 +62,7 @@ static SUPPORTED_TERMINALS: LazyLock<Vec<Terminal>> = LazyLock::new(|| {
4462
.map(|(name, program, separator_arg)| Terminal {
4563
name: name.to_string(),
4664
program: program.to_string(),
65+
extra_args: vec![],
4766
separator_arg: separator_arg.to_string(),
4867
read_only: true,
4968
})
@@ -54,7 +73,7 @@ static FLATPAK_TERMINAL_CANDIDATES: LazyLock<Vec<Terminal>> = LazyLock::new(|| {
5473
let base_terminals = [
5574
("Ptyxis", "app.devsuite.Ptyxis", "--"),
5675
("GNOME Console", "org.gnome.Console", "--"),
57-
("BlackBox", "com.raggesilver.BlackBox", "--"),
76+
// ("BlackBox", "com.raggesilver.BlackBox", "--"), for some reason it doesn't work
5877
("WezTerm", "org.wezfurlong.wezterm", "start --"),
5978
("Foot", "page.codeberg.dnkl.foot", "-e"),
6079
];
@@ -64,14 +83,16 @@ static FLATPAK_TERMINAL_CANDIDATES: LazyLock<Vec<Terminal>> = LazyLock::new(|| {
6483
// Stable
6584
candidates.push(Terminal {
6685
name: format!("{} (Flatpak)", name),
67-
program: format!("flatpak run {}", app_id),
86+
program: "flatpak".to_string(),
87+
extra_args: vec!["run".to_string(), app_id.to_string()],
6888
separator_arg: separator_arg.to_string(),
6989
read_only: true,
7090
});
7191
// Devel
7292
candidates.push(Terminal {
7393
name: format!("{} Devel (Flatpak)", name),
74-
program: format!("flatpak run {}.Devel", app_id),
94+
program: "flatpak".to_string(),
95+
extra_args: vec!["run".to_string(), format!("{}.Devel", app_id)],
7596
separator_arg: separator_arg.to_string(),
7697
read_only: true,
7798
});
@@ -88,6 +109,7 @@ mod imp {
88109
pub list: RefCell<Vec<Terminal>>,
89110
pub custom_list_path: PathBuf,
90111
pub command_runner: OnceCell<CommandRunner>,
112+
pub flatpak_terminals_query: Query<Vec<Terminal>>,
91113
}
92114

93115
impl Default for TerminalRepository {
@@ -97,6 +119,9 @@ mod imp {
97119
list: RefCell::new(vec![]),
98120
custom_list_path,
99121
command_runner: OnceCell::new(),
122+
flatpak_terminals_query: Query::new("flatpak_terminals".into(), || async {
123+
Ok(vec![])
124+
}),
100125
}
101126
}
102127
}
@@ -125,7 +150,7 @@ impl TerminalRepository {
125150
let this: Self = glib::Object::builder().build();
126151
this.imp()
127152
.command_runner
128-
.set(command_runner)
153+
.set(command_runner.clone())
129154
.map_err(|_| "command runner already set")
130155
.unwrap();
131156

@@ -142,60 +167,71 @@ impl TerminalRepository {
142167
list.sort_by(|a, b| a.name.cmp(&b.name));
143168
this.imp().list.replace(list);
144169

170+
// Set up the flatpak terminals query fetcher
171+
let runner = command_runner.clone();
172+
this.imp()
173+
.flatpak_terminals_query
174+
.set_fetcher(move || {
175+
let runner = runner.clone();
176+
async move { Self::fetch_flatpak_terminals(&runner).await }
177+
});
178+
179+
// Connect to query success to update the terminal list
145180
let this_clone = this.clone();
146-
glib::MainContext::default().spawn_local(async move {
147-
this_clone.discover_flatpak_terminals().await;
181+
this.flatpak_terminals_query().connect_success(move |terminals| {
182+
this_clone.merge_flatpak_terminals(terminals.clone());
148183
});
149184

150185
this
151186
}
152187

153-
pub async fn discover_flatpak_terminals(&self) {
154-
let Some(runner) = self.imp().command_runner.get() else {
155-
return;
156-
};
157-
188+
async fn fetch_flatpak_terminals(runner: &CommandRunner) -> anyhow::Result<Vec<Terminal>> {
158189
// Get list of installed flatpaks
159190
let mut cmd = Command::new_with_args("flatpak", ["list", "--app", "--columns=application"]);
160191
cmd.stdout = FdMode::Pipe;
161192
cmd.stderr = FdMode::Pipe;
162193

163-
let Ok(output) = runner.output(cmd).await else {
164-
return;
165-
};
166-
167-
let stdout = String::from_utf8_lossy(&output.stdout);
168-
let installed_apps: HashSet<&str> = stdout.lines().collect();
194+
let output = runner.output_string(cmd).await?;
195+
let installed_apps: HashSet<&str> = output.lines().collect();
169196

170197
let mut found_terminals = Vec::new();
171198
for terminal in FLATPAK_TERMINAL_CANDIDATES.iter() {
172-
// Extract app_id from program "flatpak run <app_id>"
173-
if let Some(app_id) = terminal.program.split_whitespace().nth(2) {
174-
if installed_apps.contains(app_id) {
199+
// Extract app_id from extra_args (e.g., ["run", "org.gnome.Console"])
200+
if let Some(app_id) = terminal.extra_args.get(1) {
201+
if installed_apps.contains(app_id.as_str()) {
175202
found_terminals.push(terminal.clone());
176203
}
177204
}
178205
}
179206

180-
if !found_terminals.is_empty() {
181-
let mut list = self.imp().list.borrow_mut();
182-
// Build a set of existing programs to avoid duplicates
183-
let existing_programs: HashSet<&str> =
184-
list.iter().map(|t| t.program.as_str()).collect();
185-
186-
// Only add terminals that don't already exist
187-
let new_terminals: Vec<Terminal> = found_terminals
188-
.into_iter()
189-
.filter(|t| !existing_programs.contains(t.program.as_str()))
190-
.collect();
191-
192-
if !new_terminals.is_empty() {
193-
list.extend(new_terminals);
194-
list.sort_by(|a, b| a.name.cmp(&b.name));
195-
drop(list);
196-
self.emit_by_name::<()>("terminals-changed", &[]);
197-
}
207+
Ok(found_terminals)
208+
}
209+
210+
fn merge_flatpak_terminals(&self, terminals: Vec<Terminal>) {
211+
if terminals.is_empty() {
212+
return;
198213
}
214+
215+
let mut list = self.imp().list.borrow_mut();
216+
// Build a set of existing terminal identifiers to avoid duplicates
217+
let existing_ids: HashSet<String> = list.iter().map(|t| t.full_command_id()).collect();
218+
219+
// Only add terminals that don't already exist
220+
let new_terminals: Vec<Terminal> = terminals
221+
.into_iter()
222+
.filter(|t| !existing_ids.contains(&t.full_command_id()))
223+
.collect();
224+
225+
if !new_terminals.is_empty() {
226+
list.extend(new_terminals);
227+
list.sort_by(|a, b| a.name.cmp(&b.name));
228+
drop(list);
229+
self.emit_by_name::<()>("terminals-changed", &[]);
230+
}
231+
}
232+
233+
pub fn flatpak_terminals_query(&self) -> Query<Vec<Terminal>> {
234+
self.imp().flatpak_terminals_query.clone()
199235
}
200236

201237
pub fn is_read_only(&self, name: &str) -> bool {
@@ -248,7 +284,7 @@ impl TerminalRepository {
248284
.list
249285
.borrow()
250286
.iter()
251-
.find(|x| x.program == program)
287+
.find(|x| x.program == program || x.full_command_id() == program)
252288
.cloned()
253289
}
254290

src/dialogs/preferences_dialog.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,22 @@ mod imp {
9292

9393
terminal_group.add(&terminal_combo_row);
9494

95+
// Connect to terminals-changed signal to update UI when terminals change
96+
obj.root_store().terminal_repository().connect_closure(
97+
"terminals-changed",
98+
false,
99+
glib::closure_local!(
100+
#[weak]
101+
obj,
102+
#[weak]
103+
terminal_combo_row,
104+
move |_: crate::backends::supported_terminals::TerminalRepository| {
105+
terminal_combo_row.rebuild_terminals_list();
106+
obj.update_delete_button_state();
107+
}
108+
),
109+
);
110+
95111
// Initialize add terminal button
96112
self.add_terminal_btn.set_label(&gettext("Add Custom"));
97113
self.add_terminal_btn.add_css_class("pill");
@@ -227,9 +243,12 @@ glib::wrapper! {
227243

228244
impl PreferencesDialog {
229245
pub fn new(root_store: RootStore) -> Self {
230-
glib::Object::builder()
231-
.property("root-store", root_store)
232-
.build()
246+
let this = glib::Object::builder()
247+
.property("root-store", root_store.clone())
248+
.build();
249+
250+
root_store.terminal_repository().flatpak_terminals_query().refetch();
251+
this
233252
}
234253

235254
fn update_delete_button_state(&self) {
@@ -293,7 +312,7 @@ impl PreferencesDialog {
293312
if let Some(terminal_combo_row) =
294313
this.imp().terminal_combo_row.borrow().as_ref()
295314
{
296-
terminal_combo_row.reload_terminals();
315+
terminal_combo_row.rebuild_terminals_list();
297316
terminal_combo_row.set_selected_by_name(
298317
&this
299318
.root_store()
@@ -415,6 +434,7 @@ impl PreferencesDialog {
415434
let terminal = supported_terminals::Terminal {
416435
name,
417436
program,
437+
extra_args: vec![],
418438
separator_arg,
419439
read_only: false,
420440
};
@@ -431,7 +451,7 @@ impl PreferencesDialog {
431451
if let Some(terminal_combo_row) =
432452
this.imp().terminal_combo_row.borrow().as_ref()
433453
{
434-
terminal_combo_row.reload_terminals();
454+
terminal_combo_row.rebuild_terminals_list();
435455
terminal_combo_row.set_selected_by_name(&terminal.name);
436456
}
437457

src/models/root_store.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ impl RootStore {
521521
};
522522
let mut spawn_cmd = Command::new(supported_terminal.program);
523523
spawn_cmd
524+
.args(supported_terminal.extra_args)
524525
.arg(supported_terminal.separator_arg)
525526
.arg(cmd.program.clone())
526527
.args(cmd.args.clone());
@@ -577,7 +578,8 @@ impl RootStore {
577578

578579
// Try running a simple command to validate the terminal
579580
let mut cmd = Command::new(terminal.program.clone());
580-
cmd.arg(terminal.separator_arg)
581+
cmd.args(terminal.extra_args.clone())
582+
.arg(terminal.separator_arg)
581583
.arg("echo")
582584
.arg("DistroShelf terminal validation");
583585

src/widgets/terminal_combo_row.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ mod imp {
5757
self.selected_item_signal_handler
5858
.replace(Some(signal_handler));
5959

60-
obj.reload_terminals();
60+
obj.rebuild_terminals_list();
6161

6262
obj.root_store().terminal_repository().connect_closure(
6363
"terminals-changed",
@@ -66,7 +66,7 @@ mod imp {
6666
#[strong]
6767
obj,
6868
move |_: TerminalRepository| {
69-
obj.reload_terminals();
69+
obj.rebuild_terminals_list();
7070
}
7171
),
7272
);
@@ -153,7 +153,7 @@ impl TerminalComboRow {
153153
}
154154
}
155155
}
156-
pub fn reload_terminals(&self) {
156+
pub fn rebuild_terminals_list(&self) {
157157
let terminals = self
158158
.root_store()
159159
.clone()

0 commit comments

Comments
 (0)