From 83525f64c96ae8945b87f2cd7051e4e5115c558b Mon Sep 17 00:00:00 2001 From: d4not <95161267+d4not@users.noreply.github.com> Date: Wed, 27 May 2026 23:20:41 -0700 Subject: [PATCH] fix: prevent CPU-spin in Sidebar leave handler on inactive Wayland workspace (#13897) When the OrcaSlicer window is on an inactive Hyprland (or any Wayland compositor that keeps surfaces mapped while hidden) workspace, GTK keeps delivering synthetic leave-notify events to the printer-preset row. The wxEVT_LEAVE_WINDOW handler at Plater.cpp:1855 calls wxFindWindowAtPoint(), which walks the entire wxWidgets window tree calling IsShown() / gtk_widget_get_child_visible() on each widget, then Hide()s the edit button and triggers a Layout() of the parent panel. The Hide()+Layout() re-fires more leave events, creating a feedback loop that pegs a CPU core at 100% indefinitely. GDB attached to a frozen process confirmed the main thread stuck in: wxFindWindowAtPoint (recursing through widget tree) -> wxWindow::IsShown -> gtk_widget_get_child_visible ... Sidebar::Sidebar(Plater*)::$_14 <- the leave handler lambda wxEvtHandler::SafelyProcessEvent wxGTKImpl::WindowLeaveCallback gtk_main_do_event ... IsShownOnScreen() can't be used as a guard here because GTK on Wayland reports widgets as visible even when the toplevel surface is on an inactive workspace (see existing comment at Plater.cpp:9304). Fix: state-based short-circuit. If btn_edit_printer is already hidden, the handler has no transition to perform - skip the expensive tree walk and the Hide()+Layout() that would re-trigger the feedback loop. After the first leave event, every subsequent leave event is O(1). Refs: - #12387 (open issue with matching setup: Arch + Hyprland + RTX 3060 + Bambu A1) - #11196 (introduced the hover-edit-button feature in Nov 2025) --- src/slic3r/GUI/Plater.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8d46b6dc3b..f16f655ee6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1853,6 +1853,14 @@ Sidebar::Sidebar(Plater *parent) 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());