diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index c4f13e5cb..07a55a861 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -271,20 +271,12 @@ Item { Settings.data.dock.pinnedApps = pinnedApps; } - // Deferred to next event-loop iteration via Timer { interval: 0 } to avoid - // re-entrant incubation: Qt.callLater() can still fire within the same event - // processing cycle, so it is not sufficient. localWorkspaces.append() inside - // refreshWorkspaces() causes the Repeater to create WorkspacePill delegates - // mid-incubation, corrupting the V4 heap (SIGSEGV in QV4::Object::insertMember). - Timer { - id: refreshTimer - interval: 0 - onTriggered: root.refreshWorkspaces() - } - + // Deferred via Qt.callLater to avoid synchronous ListModel mutations during + // signal cascades. Qt.callLater deduplicates by function identity, so rapid + // calls from multiple signal handlers coalesce into a single refresh. function scheduleRefresh() { if (!root.isDestroying) - refreshTimer.restart(); + Qt.callLater(root.refreshWorkspaces); } Component.onCompleted: scheduleRefresh() diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index d971681ae..644032ce9 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -28,11 +28,9 @@ Variants { property ListModel notificationModel: NotificationService.popupModel - // Deferred activation to prevent re-entrant QML incubation crash. - // Direct binding to notificationModel.count would activate the Loader - // synchronously during ListModel.insert(), causing nested incubation - // (Loader + inner Repeater both processing the model) which crashes - // the V4 engine in QV4::Object::insertMember. + // Deferred activation via Qt.callLater to avoid activating the Loader + // synchronously during ListModel.insert() (which would cause nested + // incubation with the inner Repeater). property bool shouldBeActive: false active: shouldBeActive || delayTimer.running @@ -43,12 +41,8 @@ Variants { repeat: false } - // Deferred activation timer - activates Loader on next event loop iteration - Timer { - id: activationTimer - interval: 0 - repeat: false - onTriggered: root.shouldBeActive = true + function activate() { + shouldBeActive = true; } Connections { @@ -56,7 +50,7 @@ Variants { function onCountChanged() { if (notificationModel.count > 0) { if (!root.shouldBeActive) { - activationTimer.restart(); + Qt.callLater(root.activate); } } else if (root.shouldBeActive) { root.shouldBeActive = false;