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:
d4not
2026-05-27 23:20:41 -07:00
committed by GitHub
parent ab9ad9e844
commit 83525f64c9

View File

@@ -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());