Skip to content

Commit 310c98f

Browse files
committed
Clarify unmatched output preset fallback
1 parent c3b5705 commit 310c98f

7 files changed

Lines changed: 80 additions & 55 deletions

File tree

data/io.github.bhack.mini-eq.metainfo.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<release version="0.5.0" date="2026-05-06">
6868
<description>
6969
<ul>
70-
<li>Add a Default Preset fallback for outputs without a linked preset.</li>
70+
<li>Add a fallback preset for outputs without a linked preset.</li>
7171
<li>Keep manual preset choices and unsaved curve edits when outputs change.</li>
7272
<li>Add Start Active at Login and improve analyzer band resolution.</li>
7373
</ul>

docs/release.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,12 @@ and with AT-SPI or live smoke when they require real GTK behavior:
5555
current curve understandable as an unsaved copy.
5656
- Link, unlink, miss, and modify auto presets for both port-scoped and
5757
output-scoped targets.
58-
- Set, miss, and clear the default preset.
58+
- Set, miss, and clear the unmatched-output fallback preset.
5959
- Change output while a curve is clean, modified, auto-applied, missing, or
6060
unavailable.
6161
- Turn Monitor on/off and freeze/unfreeze it without leaving hidden frozen
6262
state behind.
63-
- Start the app with auto/default preset and auto-route inputs and verify the
63+
- Start the app with auto/fallback preset and auto-route inputs and verify the
6464
visible window appears only after startup state is applied.
6565
- Check Shell extension/D-Bus state after preset, output, background, and
6666
window-visibility changes.

src/mini_eq/core.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,12 @@ def get_default_preset_name() -> str | None:
475475
return default_preset
476476

477477

478+
# The JSON key remains "default" for compatibility; the UI presents the same
479+
# value as the unmatched-output fallback preset.
480+
def get_output_preset_fallback_name() -> str | None:
481+
return get_default_preset_name()
482+
483+
478484
def set_output_preset_link(sink_name: str, preset_name: str) -> str:
479485
output_key = str(sink_name).strip()
480486
if not output_key:
@@ -515,12 +521,20 @@ def set_default_preset_name(preset_name: str) -> str:
515521
return default_preset
516522

517523

524+
def set_output_preset_fallback_name(preset_name: str) -> str:
525+
return set_default_preset_name(preset_name)
526+
527+
518528
def clear_default_preset_name() -> str | None:
519529
links, previous_default = load_output_preset_config()
520530
write_output_preset_config(links)
521531
return previous_default
522532

523533

534+
def clear_output_preset_fallback_name() -> str | None:
535+
return clear_default_preset_name()
536+
537+
524538
def load_mini_eq_preset_file(path: str | Path) -> dict[str, object]:
525539
file_path = Path(path)
526540
if not file_path.is_file():

src/mini_eq/window_presets.py

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,19 @@
1515
DEFAULT_ACTIVE_BANDS,
1616
PRESET_FILE_SUFFIX,
1717
PRESET_VERSION,
18-
clear_default_preset_name,
18+
clear_output_preset_fallback_name,
1919
clear_output_preset_link,
2020
delete_preset_file,
2121
ensure_json_suffix,
2222
fader_band_count_for_profile,
23-
get_default_preset_name,
23+
get_output_preset_fallback_name,
2424
get_output_preset_link,
2525
list_preset_names,
2626
load_mini_eq_preset_file,
2727
preset_path_for_name,
2828
preset_payload_state_signature,
2929
sanitize_preset_name,
30-
set_default_preset_name,
30+
set_output_preset_fallback_name,
3131
set_output_preset_link,
3232
write_mini_eq_preset_file,
3333
)
@@ -155,9 +155,9 @@ def output_preset_link_name(self) -> str | None:
155155
except Exception:
156156
return None
157157

158-
def default_preset_name(self) -> str | None:
158+
def fallback_preset_name(self) -> str | None:
159159
try:
160-
return get_default_preset_name()
160+
return get_output_preset_fallback_name()
161161
except Exception:
162162
return None
163163

@@ -387,7 +387,7 @@ def preset_panel_ui_state(self) -> PresetPanelUiState:
387387
revert_signature=revert_signature,
388388
)
389389
reset_visible = not neutral
390-
default_preset = self.default_preset_name()
390+
default_preset = self.fallback_preset_name()
391391
default_set_visible = clean_named_preset
392392
default_clear_visible = default_preset is not None
393393
curve_group_visible = has_named_preset or revert_visible or reset_visible
@@ -612,6 +612,12 @@ def refresh_preset_actions(self, state: PresetPanelUiState | None = None) -> Non
612612

613613
self.set_preset_widget_visible("default_preset_set_button", state.default_set_visible)
614614
self.set_preset_widget_visible("default_preset_clear_button", state.default_clear_visible)
615+
self.default_preset_set_button.set_sensitive(state.default_set_visible)
616+
self.default_preset_set_button.set_tooltip_text("Use this preset when no auto preset matches")
617+
self.default_preset_clear_button.set_sensitive(state.default_clear_visible)
618+
self.default_preset_clear_button.set_tooltip_text(
619+
"Bypass unmatched outputs instead of loading a fallback preset"
620+
)
615621

616622
self.set_preset_widget_visible("preset_default_separator", state.default_separator_visible)
617623
self.set_preset_widget_visible("preset_file_separator", state.file_separator_visible)
@@ -624,7 +630,7 @@ def refresh_preset_actions(self, state: PresetPanelUiState | None = None) -> Non
624630
self.set_preset_widget_visible("preset_delete_button", state.delete_visible)
625631
self.preset_delete_button.set_sensitive(state.delete_visible)
626632
self.update_output_preset_state()
627-
self.update_default_preset_state()
633+
self.update_fallback_preset_state()
628634

629635
def refresh_preset_library_popover(self) -> None:
630636
load_button = getattr(self, "preset_load_button", None)
@@ -698,13 +704,13 @@ def sync_preset_combo_selection(self) -> None:
698704
finally:
699705
self.updating_preset_combo = False
700706

701-
def update_default_preset_state(self) -> None:
707+
def update_fallback_preset_state(self) -> None:
702708
label = getattr(self, "default_preset_state_label", None)
703709
set_button = getattr(self, "default_preset_set_button", None)
704710
clear_button = getattr(self, "default_preset_clear_button", None)
705711

706712
try:
707-
default_preset = get_default_preset_name()
713+
default_preset = get_output_preset_fallback_name()
708714
except Exception as exc:
709715
if label is not None:
710716
label.set_text("Unavailable")
@@ -725,17 +731,17 @@ def update_default_preset_state(self) -> None:
725731
return
726732

727733
if default_preset is None:
728-
label.set_text("None")
729-
label.set_tooltip_text("No default preset")
734+
label.set_text("Bypass")
735+
label.set_tooltip_text("Unmatched outputs use no fallback preset.")
730736
return
731737

732738
if default_preset in self.preset_names:
733739
label.set_text(default_preset)
734-
label.set_tooltip_text("Used when the selected output has no auto preset")
740+
label.set_tooltip_text("Used when the active output has no auto preset.")
735741
return
736742

737743
label.set_text("Missing")
738-
label.set_tooltip_text(f"Default preset {default_preset} is unavailable")
744+
label.set_tooltip_text(f"Fallback preset {default_preset} is unavailable")
739745

740746
def keep_current_curve_as_unsaved_copy(self, preset_name: str) -> None:
741747
preserve_revert_baseline = (
@@ -917,7 +923,7 @@ def apply_output_preset_for_current_output(
917923
self.notify_control_state_changed()
918924
return announce_no_output_preset
919925

920-
default_preset = get_default_preset_name()
926+
default_preset = get_output_preset_fallback_name()
921927
should_apply_default_preset = default_preset is not None and (
922928
reset_auto_preset_without_link or self.current_preset_name is None
923929
)
@@ -927,19 +933,19 @@ def apply_output_preset_for_current_output(
927933
default_preset,
928934
auto=True,
929935
output_preset_auto=False,
930-
status_message="Default preset applied",
936+
status_message="Fallback preset applied",
931937
)
932938
except Exception:
933939
self.output_preset_auto_applied = False
934940
self.output_preset_curve_auto_loaded = False
935941
self.update_preset_state()
936-
self.set_status("Default preset unavailable")
942+
self.set_status("Fallback preset unavailable")
937943
self.notify_control_state_changed()
938944
else:
939945
return True
940946

941947
if reset_auto_preset_without_link:
942-
self.reset_curve_to_neutral("Reset to neutral")
948+
self.reset_curve_to_neutral("Unmatched output bypassed")
943949
return True
944950

945951
self.output_preset_auto_applied = False
@@ -1141,7 +1147,7 @@ def on_use_preset_for_output_clicked(self, _button: Gtk.Widget) -> None:
11411147
except Exception as exc:
11421148
self.set_status(str(exc))
11431149

1144-
def on_use_preset_as_default_clicked(self, _button: Gtk.Widget) -> None:
1150+
def on_use_preset_as_fallback_clicked(self, _button: Gtk.Widget) -> None:
11451151
if self.current_preset_name is None:
11461152
self.set_status("Choose a preset first")
11471153
return
@@ -1150,24 +1156,24 @@ def on_use_preset_as_default_clicked(self, _button: Gtk.Widget) -> None:
11501156
return
11511157

11521158
try:
1153-
set_default_preset_name(self.current_preset_name)
1159+
set_output_preset_fallback_name(self.current_preset_name)
11541160
self.output_preset_curve_auto_loaded = False
11551161
self.update_preset_state()
1156-
self.set_status("Default preset set")
1162+
self.set_status("Fallback preset set")
11571163
self.notify_control_state_changed()
11581164
except Exception as exc:
11591165
self.set_status(str(exc))
11601166
self.notify_control_state_changed()
11611167

1162-
def on_clear_default_preset_clicked(self, _button: Gtk.Widget) -> None:
1168+
def on_bypass_unmatched_outputs_clicked(self, _button: Gtk.Widget) -> None:
11631169
try:
1164-
removed = clear_default_preset_name()
1170+
removed = clear_output_preset_fallback_name()
11651171
self.output_preset_curve_auto_loaded = False
11661172
self.update_preset_state()
11671173
if removed:
1168-
self.set_status("Default preset cleared")
1174+
self.set_status("Unmatched outputs bypassed")
11691175
else:
1170-
self.set_status("No default preset")
1176+
self.set_status("Unmatched outputs already bypassed")
11711177
self.notify_control_state_changed()
11721178
except Exception as exc:
11731179
self.set_status(str(exc))

src/mini_eq/window_utility.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ def make_preset_section(self) -> Gtk.Box:
107107
self.default_preset_state_label.set_hexpand(True)
108108
self.default_preset_state_label.add_css_class("dim-label")
109109
self.default_preset_state_label.set_ellipsize(Pango.EllipsizeMode.END)
110-
set_accessible_label(self.default_preset_state_label, "Default Preset Status")
110+
set_accessible_label(self.default_preset_state_label, "Unmatched Output Fallback Status")
111111

112112
default_preset_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10)
113113
default_preset_row.add_css_class("utility-row")
114-
default_preset_label = Gtk.Label(label="Default Preset", xalign=0.0)
114+
default_preset_label = Gtk.Label(label="Fallback", xalign=0.0)
115115
default_preset_row.append(default_preset_label)
116116
default_preset_row.append(self.default_preset_state_label)
117117
preset_section.append(default_preset_row)
@@ -178,13 +178,13 @@ def make_preset_action(label: str, callback, *, destructive: bool = False) -> tu
178178
self.preset_default_separator = append_preset_separator()
179179

180180
self.default_preset_set_button, self.default_preset_set_button_label = make_preset_action(
181-
"Set as Default",
182-
self.on_use_preset_as_default_clicked,
181+
"Use as Fallback",
182+
self.on_use_preset_as_fallback_clicked,
183183
)
184184

185185
self.default_preset_clear_button, self.default_preset_clear_button_label = make_preset_action(
186-
"Clear Default",
187-
self.on_clear_default_preset_clicked,
186+
"Bypass Unmatched Outputs",
187+
self.on_bypass_unmatched_outputs_clicked,
188188
)
189189

190190
self.preset_file_separator = append_preset_separator()

tests/test_mini_eq_core.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,14 @@ def test_default_preset_roundtrip_preserves_output_links(monkeypatch: pytest.Mon
242242
monkeypatch.setattr(core, "OUTPUT_PRESET_LINKS_PATH", tmp_path / "output-presets.json")
243243
core.set_output_preset_link("alsa_output.speakers", "Speakers")
244244

245-
assert core.set_default_preset_name("../Neutral...") == "Neutral"
245+
assert core.set_output_preset_fallback_name("../Neutral...") == "Neutral"
246246
assert core.get_default_preset_name() == "Neutral"
247+
assert core.get_output_preset_fallback_name() == "Neutral"
247248
assert core.load_output_preset_links() == {"alsa_output.speakers": "Speakers"}
248249

249-
assert core.clear_default_preset_name() == "Neutral"
250+
assert core.clear_output_preset_fallback_name() == "Neutral"
250251
assert core.get_default_preset_name() is None
252+
assert core.get_output_preset_fallback_name() is None
251253
assert core.load_output_preset_links() == {"alsa_output.speakers": "Speakers"}
252254

253255

0 commit comments

Comments
 (0)