From b45d675488ace614ee8c63696231f1b737822e4b Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Sat, 5 Sep 2026 16:02:53 +0200 Subject: [PATCH] The frames now keep coming; the characters still do not MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Third measured step, and the last one I will take without a second pair of eyes. set_as_dirty() BEFORE Refresh(): GLCanvas3D's paint handler returns without rendering when the canvas is not marked dirty, so the previous commit's bare Refresh() posted paint events that drew nothing and the frames stopped anyway. With both halves the pump sustains, and the trace shows the field holding the keyboard frame after frame: [UX] frame want_text=1 want_kb=1 active=1 buf=158.74 [UX] frame want_text=1 want_kb=1 active=1 buf=158.74 (repeating) STILL OPEN, and now narrowed to one question: buf never changes. ImGui owns the keyboard and our InputText is the active item, so what is missing is upstream of ImGui — the characters are not reaching io.AddInputCharacter at all. The next thing to MEASURE (not to change) is whether wxEVT_CHAR arrives at the GL canvas in the Design tab: DesignPanel's wxEVT_CHAR_HOOK Skips digits while inline_busy(), but Skip only helps if the focused widget is the canvas, and nothing has yet proved that it is at the moment the keys are sent. Three attempts have now gone into this one point. Per the standing rule that is where solo iteration stops. Deployed binary restored to 00d6c191dc (md5 0eeb9a58cef5) — nothing from this branch is installed. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011FbJKJAJxxkhDTs9XdZzKA --- src/slic3r/GUI/CAD/DesignCanvas.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/CAD/DesignCanvas.cpp b/src/slic3r/GUI/CAD/DesignCanvas.cpp index e8b370eb6b..40ac171264 100644 --- a/src/slic3r/GUI/CAD/DesignCanvas.cpp +++ b/src/slic3r/GUI/CAD/DesignCanvas.cpp @@ -87,7 +87,21 @@ DesignCanvas::DesignCanvas(wxWindow* parent) // The tool draws it: it owns the frame's ImGui pass and the render scale. Handing it a raw // pointer rather than the unique_ptr keeps the ownership where it was. m_sketch_tool.inline_editor = m_inline_editor.get(); - m_inline_editor->request_frame = [this] { request_repaint(); }; + // SCHEDULE a paint, do not render one. request_repaint() renders SYNCHRONOUSLY on software + // GL, and this callback runs from inside DesignSketchTool::render() — so using it here asks + // for a render from within a render. The frames stopped after nine, which is what a + // re-entrancy guard giving up looks like. Refresh() posts a paint event instead: the current + // frame finishes, the event loop runs (which is where ImGui's queued characters are consumed), + // and the next frame starts clean. + m_inline_editor->request_frame = [this] { + // BOTH halves, and the dirty flag first: GLCanvas3D's paint handler returns without + // rendering when the canvas is not marked dirty, so a bare Refresh() posts an event that + // draws nothing and the frames still stop. request_repaint() does exactly this pair on + // the hardware path; what it must NOT do here is its software path, which renders + // synchronously — and this callback runs from inside render(). + if (m_canvas) m_canvas->set_as_dirty(); + if (m_canvas_widget) m_canvas_widget->Refresh(false); + }; m_sketch_tool.on_inline_edit = [this](wxPoint screen_px, double current, const std::string& title, std::function commit,