@@ -806,6 +806,39 @@ def test_output_preset_actions_use_route_key_when_available(monkeypatch, tmp_pat
806806 assert test_window .statuses [- 1 ] == "Auto preset cleared"
807807
808808
809+ def test_output_scope_state_follows_same_sink_route_change (monkeypatch , tmp_path ) -> None :
810+ monkeypatch .setattr (core , "PRESET_STORAGE_DIR" , tmp_path / "presets" )
811+ monkeypatch .setattr (core , "OUTPUT_PRESET_LINKS_PATH" , tmp_path / "output-presets.json" )
812+ controller = make_controller ("alsa_output.internal" )
813+ route = SimpleNamespace (
814+ description = "Headphones" ,
815+ name = "analog-output-headphones" ,
816+ output_preset_key = "pipewire-route:v1:device=alsa_card.test;route=analog-output-headphones;route-device=6" ,
817+ )
818+
819+ def output_preset_target ():
820+ return SimpleNamespace (
821+ output_key = controller .output_sink ,
822+ route = route ,
823+ keys = (route .output_preset_key , controller .output_sink ),
824+ link_key = route .output_preset_key ,
825+ has_route_key = True ,
826+ )
827+
828+ controller .output_preset_target = output_preset_target
829+ test_window = OutputPresetWindow (controller )
830+
831+ test_window .update_output_preset_state ()
832+ assert test_window .output_scope_state_label .text == "Headphones"
833+
834+ route .description = "Speakers"
835+ route .name = "analog-output-speaker"
836+ route .output_preset_key = "pipewire-route:v1:device=alsa_card.test;route=analog-output-speaker;route-device=6"
837+
838+ test_window .update_output_preset_state ()
839+ assert test_window .output_scope_state_label .text == "Speakers"
840+
841+
809842def test_deleting_only_loaded_preset_keeps_curve_and_allows_neutral_reset (monkeypatch , tmp_path ) -> None :
810843 monkeypatch .setattr (core , "PRESET_STORAGE_DIR" , tmp_path / "presets" )
811844 monkeypatch .setattr (core , "OUTPUT_PRESET_LINKS_PATH" , tmp_path / "output-presets.json" )
@@ -1134,6 +1167,54 @@ def test_pipewire_observed_output_change_runs_output_preset_handling() -> None:
11341167 assert fake_window .last_output_preset_sink_name == "alsa_output.usb"
11351168
11361169
1170+ def test_pipewire_observed_port_scope_change_runs_output_preset_handling () -> None :
1171+ calls : list [object ] = []
1172+ old_route_key = "pipewire-route:v1:device=alsa_card.test;route=analog-output-headphones;route-device=6"
1173+ new_route_key = "pipewire-route:v1:device=alsa_card.test;route=analog-output-speaker;route-device=6"
1174+ target = SimpleNamespace (
1175+ link_key = new_route_key ,
1176+ keys = (new_route_key , "alsa_output.internal" ),
1177+ )
1178+ fake_window = SimpleNamespace (
1179+ ui_shutting_down = False ,
1180+ controller = SimpleNamespace (
1181+ output_sink = "alsa_output.internal" ,
1182+ follow_default_output = True ,
1183+ get_default_output_sink_name = lambda : "alsa_output.internal" ,
1184+ get_sink = lambda _sink_name : None ,
1185+ ),
1186+ last_output_preset_sink_name = "alsa_output.internal" ,
1187+ last_output_preset_target_identity = old_route_key ,
1188+ output_preset_auto_applied = True ,
1189+ output_preset_curve_auto_loaded = True ,
1190+ post_present_ready = True ,
1191+ list_visible_output_sinks = lambda : [],
1192+ build_output_sink_labels = lambda _sinks : [],
1193+ follow_default_output_label = lambda : "Follow system output" ,
1194+ output_sink_names = [],
1195+ output_sink_labels = [],
1196+ output_sink_model = FakeModel (),
1197+ output_combo = FakeCombo (),
1198+ updating_output_combo = False ,
1199+ output_preset_target = lambda : target ,
1200+ update_preset_state = lambda : calls .append ("preset-state" ),
1201+ update_info_label = lambda : calls .append ("info" ),
1202+ update_status_summary = lambda : calls .append ("summary" ),
1203+ apply_output_preset_for_current_output = lambda ** kwargs : calls .append (("auto" , kwargs )),
1204+ )
1205+
1206+ window .MiniEqWindow .refresh_output_sinks (fake_window )
1207+
1208+ assert calls == [
1209+ "preset-state" ,
1210+ "info" ,
1211+ "summary" ,
1212+ ("auto" , {"reset_auto_preset_without_link" : True , "announce_no_output_preset" : True }),
1213+ ]
1214+ assert fake_window .last_output_preset_sink_name == "alsa_output.internal"
1215+ assert fake_window .last_output_preset_target_identity == new_route_key
1216+
1217+
11371218def test_manual_output_refresh_updates_selector_without_handling_observed_output_change () -> None :
11381219 calls : list [object ] = []
11391220 fake_window = SimpleNamespace (
0 commit comments