From 602ec0b2cefa3fc0e7d167d1e6f819b6b9e25a6d Mon Sep 17 00:00:00 2001 From: spr0u <204455541+spr0u@users.noreply.github.com> Date: Sat, 6 Jun 2026 07:39:40 -0500 Subject: [PATCH] fix: freezing caused by dynamically hidden printer edit button (#14010) * fix: freezing caused by dynamically hidden printer edit button * track hover state of individual widgets --- src/slic3r/GUI/Plater.cpp | 74 +++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 41 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 66f8481bce..b694d219d2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1796,39 +1796,35 @@ Sidebar::Sidebar(Plater *parent) }); */ // ORCA use Show/Hide to gain text area instead using blank icon. also manages hover effect for border + auto printer_preset_hovered = std::make_shared>(); for (wxWindow *w : std::initializer_list{p->panel_printer_preset, p->btn_edit_printer, p->image_printer, p->combo_printer}) { - w->Bind(wxEVT_ENTER_WINDOW, [this, panel_color](wxMouseEvent &e) { + w->Bind(wxEVT_ENTER_WINDOW, [this, w, panel_color, printer_preset_hovered](wxMouseEvent &e) { + printer_preset_hovered->insert(w); if(!p->combo_printer->HasFocus()) p->panel_printer_preset->SetBorderColor(panel_color.bd_hover); - if(!p->btn_edit_printer->IsShown()){ - p->btn_edit_printer->Show(); - p->panel_printer_preset->Layout(); - } e.Skip(); }); - w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) { - // Orca: if the edit button is already hidden the handler has no - // state to change, so skip the expensive wxFindWindowAtPoint tree - // walk. Without this guard, when the parent window is on an - // inactive Hyprland/Wayland workspace, GTK keeps delivering - // synthetic leave events and the Hide()+Layout() below re-enters - // the same handler in a feedback loop that pegs a CPU core. - // (IsShownOnScreen() can't be used here — see Plater.cpp:9304.) - if (!p->btn_edit_printer->IsShown()) { e.Skip(); return; } - // Use event-relative coords instead of wxGetMousePosition() which - // returns (0,0) on Wayland for global screen coordinates. - wxWindow* evtObj = dynamic_cast(e.GetEventObject()); - wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition(); - wxWindow* next_w = wxFindWindowAtPoint(screenPos); - if (!next_w || !p->panel_printer_preset->IsDescendant(next_w)){ - if(!p->combo_printer->HasFocus()) - p->panel_printer_preset->SetBorderColor(panel_color.bd_normal); - p->btn_edit_printer->Hide(); - p->panel_printer_preset->Layout(); - } + w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color, printer_preset_hovered](wxMouseEvent &e) { + printer_preset_hovered->erase(w); + if (printer_preset_hovered->empty() && !p->combo_printer->HasFocus()) + p->panel_printer_preset->SetBorderColor(panel_color.bd_normal); e.Skip(); }); } + // Perform show/hide in wxEVT_IDLE after enter/leave events have settled. + // This prevents the extraneous enter/leave events generated by the + // layout change itself from causing a feedback loop. + Bind(wxEVT_IDLE, [this, printer_preset_hovered](wxIdleEvent &e) { + auto hovered = !printer_preset_hovered->empty(); + if (p->btn_edit_printer->IsShown() != hovered) { + if (hovered) { + p->btn_edit_printer->Show(); + } else { + p->btn_edit_printer->Hide(); + } + p->panel_printer_preset->Layout(); + } + }); // ORCA unified Nozzle diameter selection p->panel_nozzle_dia = new StaticBox(p->m_panel_printer_content); @@ -1874,19 +1870,17 @@ Sidebar::Sidebar(Plater *parent) p->label_nozzle_type->SetMaxSize(FromDIP(wxSize(56, -1))); // highlight border on hover + auto nozzle_dia_hovered = std::make_shared>(); for (wxWindow *w : std::initializer_list{p->panel_nozzle_dia, p->label_nozzle_title, p->label_nozzle_type, p->combo_nozzle_dia}) { - w->Bind(wxEVT_ENTER_WINDOW, [this, panel_color](wxMouseEvent &e) { + w->Bind(wxEVT_ENTER_WINDOW, [this, w, panel_color, nozzle_dia_hovered](wxMouseEvent &e) { + nozzle_dia_hovered->insert(w); if(!p->combo_nozzle_dia->HasFocus()) p->panel_nozzle_dia->SetBorderColor(panel_color.bd_hover); e.Skip(); }); - w->Bind(wxEVT_LEAVE_WINDOW, [this, panel_color](wxMouseEvent &e) { - // Use event-relative coords instead of wxGetMousePosition() which - // returns (0,0) on Wayland for global screen coordinates. - wxWindow* evtObj = dynamic_cast(e.GetEventObject()); - wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition(); - wxWindow* next_w = wxFindWindowAtPoint(screenPos); - if (!p->combo_nozzle_dia->HasFocus() && (!next_w || !p->panel_nozzle_dia->IsDescendant(next_w))) + w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color, nozzle_dia_hovered](wxMouseEvent &e) { + nozzle_dia_hovered->erase(w); + if (nozzle_dia_hovered->empty() && !p->combo_nozzle_dia->HasFocus()) p->panel_nozzle_dia->SetBorderColor(panel_color.bd_normal); e.Skip(); }); @@ -1946,21 +1940,19 @@ Sidebar::Sidebar(Plater *parent) p->combo_printer_bed->Bind(wxEVT_KILL_FOCUS, [this, bed_focus_bg](auto& e) {bed_focus_bg(false); e.Skip();}); // highlight border on hover + auto printer_bed_hovered = std::make_shared>(); for (wxWindow *w : std::initializer_list{p->panel_printer_bed, p->image_printer_bed, p->combo_printer_bed}) { - w->Bind(wxEVT_ENTER_WINDOW, [this, w, panel_color](wxMouseEvent &e) { + w->Bind(wxEVT_ENTER_WINDOW, [this, w, panel_color, printer_bed_hovered](wxMouseEvent &e) { + printer_bed_hovered->insert(w); if(!p->combo_printer_bed->HasFocus()) p->panel_printer_bed->SetBorderColor(panel_color.bd_hover); if(w == p->image_printer_bed && !p->combo_printer_bed->is_drop_down()) // dont trigger while combo open on_enter_image_printer_bed(e); e.Skip(); }); - w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color](wxMouseEvent &e) { - // Use event-relative coords instead of wxGetMousePosition() which - // returns (0,0) on Wayland for global screen coordinates. - wxWindow* evtObj = dynamic_cast(e.GetEventObject()); - wxPoint screenPos = evtObj ? evtObj->ClientToScreen(e.GetPosition()) : wxGetMousePosition(); - wxWindow* next_w = wxFindWindowAtPoint(screenPos); - if (!p->combo_printer_bed->HasFocus() && (!next_w || !p->panel_printer_bed->IsDescendant(next_w))) + w->Bind(wxEVT_LEAVE_WINDOW, [this, w, panel_color, printer_bed_hovered](wxMouseEvent &e) { + printer_bed_hovered->erase(w); + if (printer_bed_hovered->empty() && !p->combo_printer_bed->HasFocus()) p->panel_printer_bed->SetBorderColor(panel_color.bd_normal); if(w == p->image_printer_bed) on_leave_image_printer_bed(e);