From 876d6e24995160f5742becf335451b901e7fc407 Mon Sep 17 00:00:00 2001 From: Ian Chua Date: Wed, 26 Aug 2026 17:56:49 +0800 Subject: [PATCH] fix: printer agent switching on preset change --- src/slic3r/GUI/DeviceCore/DevManager.cpp | 35 +++++++++++++----------- src/slic3r/GUI/DeviceCore/DevManager.h | 7 ++--- src/slic3r/GUI/DeviceManager.hpp | 3 ++ src/slic3r/GUI/GUI_App.cpp | 16 +++++------ src/slic3r/GUI/PresetComboBoxes.cpp | 6 ++-- src/slic3r/Utils/IPrinterAgent.hpp | 35 ++++++++++++++++++++++++ 6 files changed, 71 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/DeviceCore/DevManager.cpp b/src/slic3r/GUI/DeviceCore/DevManager.cpp index 8844303793..b1e1f7266e 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.cpp +++ b/src/slic3r/GUI/DeviceCore/DevManager.cpp @@ -264,6 +264,10 @@ namespace Slic3r /* update userMachineList info */ auto it = userMachineList.find(dev_id); if (it != userMachineList.end()) { + // A reused entry may have been created while another printer agent was active. + // The response was obtained through the current agent, so move ownership with + // the entry; otherwise agent-scoped lists hide it after a preset switch. + it->second->printer_agent_id = get_current_printer_agent_id(); if (it->second->get_dev_ip() != dev_ip || it->second->bind_state != bind_state || it->second->bind_sec_link != sec_link || @@ -294,6 +298,9 @@ namespace Slic3r // update properties /* ip changed */ obj = it->second; + // A reused LAN entry may have been discovered while another printer agent was + // active. The current discovery message establishes ownership for this agent. + obj->printer_agent_id = get_current_printer_agent_id(); if (obj->get_dev_ip().compare(dev_ip) != 0) { if ( connection_name.empty() ) { @@ -405,6 +412,9 @@ namespace Slic3r auto it = localMachineList.find(machine.dev_id); if (it != localMachineList.end()) { obj = it->second; + // insert_local_device is called by the active agent, so a reused entry must follow + // that agent as well; otherwise the agent-scoped printer list hides it. + obj->printer_agent_id = get_current_printer_agent_id(); } else { obj = new MachineObject(this, m_agent, machine.dev_name, machine.dev_id, machine.dev_ip); obj->printer_agent_id = get_current_printer_agent_id(); @@ -534,25 +544,15 @@ namespace Slic3r OnSelectedMachineChanged(previous_selected_machine, selected_machine); } - void DeviceManager::clear_other_devices(const std::string& target_agent_id) + void DeviceManager::clear_other_devices() { - // why: on agent swap, keep "My Devices" but drop the transient "Other Devices" - // Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own. - // - // Also drop "My Devices" stamped by a different agent than the one we're swapping to - // (target_agent_id, passed by the caller since the live agent hasn't been repointed yet - // at this point): otherwise a device first discovered under agent A survives every swap - // with a stale printer_agent_id, stays hidden from every agent's filtered list, and only - // gets re-tagged if something happens to delete and re-create it (e.g. account logout). - // Dropping it here instead lets the new agent's start_discovery re-insert and re-stamp it - // like any other fresh device. - const auto my = get_my_machine_list(); + // Device entries are now scoped by printer_agent_id when they are presented. Keep + // agent-owned discoveries across a switch so agents without automatic discovery (and + // plugins whose devices have not received an access code yet) do not lose their list. + // Entries without an owner are legacy/unscoped and cannot safely be shown. for (auto it = localMachineList.begin(); it != localMachineList.end();) { - const bool is_my_device = my.find(it->first) != my.end(); - const bool agent_mismatch = !target_agent_id.empty() && it->second && - it->second->printer_agent_id != target_agent_id; - if (!is_my_device || agent_mismatch) + if (!it->second || it->second->printer_agent_id.empty()) { delete it->second; it = localMachineList.erase(it); @@ -845,6 +845,9 @@ namespace Slic3r /* update field */ obj = iter->second; obj->set_dev_id(dev_id); + // A device can be rediscovered by a different agent after a preset + // switch while retaining the same MachineObject instance. + obj->printer_agent_id = get_current_printer_agent_id(); } else { diff --git a/src/slic3r/GUI/DeviceCore/DevManager.h b/src/slic3r/GUI/DeviceCore/DevManager.h index cc217cfb2a..32f93f3a1a 100644 --- a/src/slic3r/GUI/DeviceCore/DevManager.h +++ b/src/slic3r/GUI/DeviceCore/DevManager.h @@ -74,10 +74,9 @@ public: void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); } void clean_user_info(bool keep_local_selection = false); - // target_agent_id: id of the agent being swapped to (empty = no agent-mismatch check, - // just the original "drop Other Devices" behavior). Pass the incoming agent's id, not the - // live one - this runs before the live agent is repointed. - void clear_other_devices(const std::string& target_agent_id = ""); + // Retain agent-owned LAN discoveries across a switch; the active-agent list filter keeps + // entries from other agents hidden while allowing them to reappear when switched back. + void clear_other_devices(); void load_last_machine(); void update_user_machine_list_info(const std::string& provider); diff --git a/src/slic3r/GUI/DeviceManager.hpp b/src/slic3r/GUI/DeviceManager.hpp index 0408ddee41..d22d68b8a3 100644 --- a/src/slic3r/GUI/DeviceManager.hpp +++ b/src/slic3r/GUI/DeviceManager.hpp @@ -305,6 +305,9 @@ public: /** Whether this printer supports virtual trays (external/manual filament loading). * When true, vt_slot data is used by build_filament_ams_list() to include external filaments. */ bool ams_support_virtual_tray { true }; + // Filament entries supplied by a printer agent (for example, toolchanger tools) + // remain valid even when a regular status message has no vir_slot field. + bool agent_virtual_tray { false }; time_t ams_user_setting_start = 0; time_t ams_switch_filament_start = 0; AmsStatusMain ams_status_main; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 6028ada640..b91eca2052 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3951,13 +3951,9 @@ void GUI_App::set_live_printer_agent(std::shared_ptr agent) m_agent->set_user_selected_machine(""); // note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer) dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS - // why: drop stale LAN discoveries; keep My Devices, but only those belonging to the - // agent we're about to swap to, so a device stamped by the outgoing agent doesn't - // linger hidden - the new agent's start_discovery re-inserts and re-stamps it fresh. - // agent is null when clearing the live agent entirely (e.g. plugin unload); there's no - // target to filter against then, so fall back to the original "keep all My Devices" - // behavior rather than guessing. - dev->clear_other_devices(agent ? agent->get_agent_info().id : std::string()); + // why: retain agent-owned LAN discoveries so agents without automatic discovery (for + // example the Moonraker-based Qidi/Snapmaker agents) can reuse them after a switch. + dev->clear_other_devices(); } m_agent->set_printer_agent(agent); @@ -4013,8 +4009,10 @@ void GUI_App::switch_printer_agent() return; } - // The factory caches agents per ID, so an identical pointer means the agent type is unchanged. - if (m_agent->get_printer_agent() == new_printer_agent) { + // Compare the registered IDs, not only the implementation pointer. Different registry IDs + // may intentionally be backed by the same implementation object (especially for plugins). + const auto current_printer_agent = m_agent->get_printer_agent(); + if (current_printer_agent && current_printer_agent->get_agent_info().id == effective_agent_id) { // Orca: the agent type is unchanged (e.g. switching between two Moonraker/Klipper // printer presets), so the selected machine and the agent's cached device_info still // point at the previously active printer preset. Re-select the machine when the new diff --git a/src/slic3r/GUI/PresetComboBoxes.cpp b/src/slic3r/GUI/PresetComboBoxes.cpp index 2f82a5630e..2d7acb1a49 100644 --- a/src/slic3r/GUI/PresetComboBoxes.cpp +++ b/src/slic3r/GUI/PresetComboBoxes.cpp @@ -361,7 +361,8 @@ wxString PresetComboBox::get_preset_item_name(unsigned int index) return GetString(index); } - std::map machine_list = dev->get_my_machine_list(); + std::map machine_list = + dev->get_my_machine_list(dev->get_current_printer_agent_id()); if (machine_list.empty()) { assert(false); m_selected_dev_id.clear(); @@ -479,7 +480,8 @@ void PresetComboBox::add_connected_printers(std::string selected, bool alias_nam if (!dev) return; - std::map machine_list = dev->get_my_machine_list(); + std::map machine_list = + dev->get_my_machine_list(dev->get_current_printer_agent_id()); if (machine_list.empty()) return; diff --git a/src/slic3r/Utils/IPrinterAgent.hpp b/src/slic3r/Utils/IPrinterAgent.hpp index 69d8d53ce9..269c2a337b 100644 --- a/src/slic3r/Utils/IPrinterAgent.hpp +++ b/src/slic3r/Utils/IPrinterAgent.hpp @@ -12,6 +12,41 @@ #include #include +#if 1 + +struct OrcaProtocol +{ + enum CameraStreamMode { http, http_snapshot, rtsp, webrtc }; + struct Capabilities { + bool has_ams; + struct CameraInfo { + CameraStreamMode available_modes; + std::string url; + }; + + std::vector cameras; + + bool toolchanger; + int nozzle_count; + }; + + struct AMSInfo { + int slot_count; + std::vector color_info; + std::vector filament_id; + }; + + AMSInfo ams_info; + + struct Status { + std::vector nozzle_temps; + int bed_temp; + int chamber_temp; + }; +}; + +#endif + namespace Slic3r { class ICloudServiceAgent;