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)
This commit is contained in:
@@ -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<wxWindow*>(e.GetEventObject());
|
||||
|
||||
Reference in New Issue
Block a user