Conversation
Selecting a driver such as RuidaRPAAdapter without connection details crashed the app with a GTK assertion (priv->object == object in gtk_list_factory_widget_setup_factory) and left users in a crash loop at startup, because the driver choice is persisted immediately. Fixes: - bottom_panel: stop re-emitting items_changed on the unchanged WCS list model. Faking item replacements violates the list model contract and crashes GTK while it is setting up factory widgets. The model is now spliced only when the displayed content (WCS set, labels, offsets) actually changed. - laser_control_widget: only swap the laser head combo model when the head names changed instead of rebuilding it on every machine change. - controller/machine: driver rebuilds are now exclusively driven by the machine's changed signal and debounced, so bursts of edits (e.g. per-keystroke changes in the driver settings) coalesce into a single rebuild and a single connection attempt. Previously every change scheduled two concurrent rebuilds (direct schedule plus the changed listener), which could wedge the transport until restart. - general_preferences_page: populate driver settings from the driver class registry instead of the live driver instance, which is still the previous driver while a rebuild is pending. Adds regression tests for the WCS model sync and the rebuild debounce.
A cancellation landing between the task manager's early-cancel check and the creation of the internal asyncio task does not propagate to the already-running coroutine, so a superseded debounce could still reach rebuild_driver. Re-check the execution context's cancellation flag after the sleep so a cancelled rebuild never touches driver state.
Editing driver setup arguments (e.g. numeric fields) while the machine is connected tore the driver down and reconnected on every debounced change, and a fast editing burst could occasionally leave the driver disconnected. When the driver class is unchanged and the driver has a live connection, the running instance is now kept and the edited arguments are applied by the rebuild that runs once the connection is gone, e.g. after an explicit disconnect or a drop. Also reset the connection status directly in disconnect() instead of leaving it stale until the scheduled rebuild runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #415
Problem
Selecting the Ruida driver in the machine settings crashed the app with
and because the driver choice is persisted immediately, every subsequent
start crashed too (crash loop). A related report in the comments showed
the driver being rebuilt on every keystroke while editing driver
settings, eventually wedging the connection until restart.
Root causes
BottomPanel._update_wcs_ui()force-refreshed the WCS dropdown byre-emitting
items_changed(i, 1, 1)on an unchangedGtk.StringListon every
machine.changed. Faking item replacements violates the listmodel contract; GTK crashes with the above assertion when this happens
while it is setting up factory widgets (e.g. during window build at
startup, which is exactly the persisted-bad-driver crash loop).
LaserControlWidget._rebuild_head_model()replaced the head combo'sentire model on every
machine.changed, poking live widgets mid-flightin the same signal wave.
Machine.set_driver()/set_driver_args()scheduled a rebuild directlyand triggered the controller's
changedlistener, so everyconfiguration change ran two concurrent rebuild coroutines with two
connection attempts. Per-keystroke edits therefore tore down/re-created
the driver and transport repeatedly until things wedged.
Fixes
displayed content (WCS set, labels, offsets) actually changed, via a
real
Gtk.StringList.splice()— legal list model usage, no moremid-flight poking.
names changed; otherwise just the selected head's fields are re-synced.
the machine's
changedsignal (blinker) and debounced (0.3 s), sobursts of edits coalesce into a single rebuild and a single connect.
Cancellation happens during the sleep and is re-checked afterwards, so
a superseded rebuild can never touch driver state. A pending rebuild
is also cancelled by
disconnect()so it cannot silently reconnect anexplicitly disconnected machine.
connected, editing its setup arguments no longer tears it down and
reconnects. The live instance is kept; the edited arguments are applied
by the rebuild that runs once the connection is gone again (explicit
disconnect or a drop). This removes the remaining
disconnect/reconnect churn when typing into numeric driver fields.
leaving it stale until the scheduled rebuild runs.
the driver class registry instead of the live driver instance, which
is still the previous driver while a rebuild is pending.
Tests
tests/ui_gtk/doceditor/test_bottom_panel_wcs_model.py: verifies nomodel mutation on unchanged state (the the app crash when switching to the ruida driver #415 crash) and a single real
splice on offset/WCS-set changes.
TestDriverRebuildDebounceintests/machine/models/test_machine_controller.py:a burst of
set_driver_argscalls results in exactly one rebuild withthe final values.
TestKeepLiveDriverOnArgsChange: editing args of a connecteddriver keeps the live instance and connection intact, and the edited
arguments are applied after a disconnect.
Full
tests/machine(2266 passed) anduitest(853 passed) suites green,pixi run lint/formatclean.