fix(bar): attempt to avoid crash when autohide is used

This commit is contained in:
Lysec
2026-03-17 11:00:43 +01:00
parent 46a3c7e2d4
commit 311fc08ac8
4 changed files with 40 additions and 9 deletions
+10
View File
@@ -85,6 +85,12 @@ Item {
property ListModel centerWidgetsModel: ListModel {}
property ListModel rightWidgetsModel: ListModel {}
// Guard: set when Bar is destroyed; prevents Qt.callLater callbacks from running
// during/after teardown (avoids SIGSEGV in QV4::Object::insertMember when rapid
// workspace switch causes load/unload overlap with async widget incubation)
property bool _destroyed: false
Component.onDestruction: root._destroyed = true
// Sync a ListModel with widget data, preserving delegates when only settings change
function syncWidgetModel(model, newWidgets) {
var validWidgets = filterValidWidgets(newWidgets);
@@ -134,6 +140,8 @@ Item {
}
function _syncFromRevision() {
if (root._destroyed)
return;
var widgets = Settings.getBarWidgetsForScreen(screen?.name);
if (widgets) {
syncWidgetModel(leftWidgetsModel, widgets.left);
@@ -152,6 +160,8 @@ Item {
}
function _initModels() {
if (root._destroyed)
return;
var widgets = Settings.getBarWidgetsForScreen(screen?.name);
if (widgets) {
syncWidgetModel(leftWidgetsModel, widgets.left);
+4
View File
@@ -91,6 +91,10 @@ Item {
onLoaded: {
if (!item)
return;
// Guard: if parent chain is torn down (Bar content unload during rapid workspace
// switch), skip registration to avoid SIGSEGV in QV4 during async incubation
if (!root.parent || !root.parent.parent || !widgetScreen?.name)
return;
Logger.d("BarWidgetLoader", "Loading widget", widgetId, "on screen:", widgetScreen.name);
+3 -2
View File
@@ -152,10 +152,11 @@ PanelWindow {
// start the unload timer), unmapping the Wayland surface mid-animation.
property bool contentLoaded: false
// Timer to delay unload until after fade animation
// Timer to delay unload until after fade animation.
// Extra buffer (250ms) when auto-hide to reduce race with rapid workspace switch (SIGSEGV in QV4).
Timer {
id: unloadTimer
interval: Style.animationFast + 50
interval: Style.animationFast + (barWindow.autoHide ? 250 : 50)
onTriggered: {
// Only unload if still hidden AND not about to show (prevents unload/reload race)
if (barWindow.isHidden && !showTimer.running) {
+23 -7
View File
@@ -196,6 +196,25 @@ Singleton {
// Track last workspace ID to detect actual workspace changes
property var lastWorkspaceId: null
// Debounce rapid workspace switches to reduce load/unload races (SIGSEGV in QV4)
property string _pendingWorkspaceScreen: ""
Timer {
id: workspaceDebounceTimer
interval: 80
repeat: false
onTriggered: {
var screen = root._pendingWorkspaceScreen;
root._pendingWorkspaceScreen = "";
if (screen) {
setScreenHidden(screen, false);
if (!root.isBarHovered(screen)) {
barHoverStateChanged(screen, false);
}
}
}
}
// Workspace switch handler - directly show bar on the focused workspace screen
Connections {
target: CompositorService
@@ -220,13 +239,10 @@ Singleton {
var screenName = ws.output || "";
Logger.d("BarService", "Workspace switched to:", currentWsId, "on screen:", screenName);
// Show bar immediately
setScreenHidden(screenName, false);
// Only trigger hideTimer if not already hovered (e.g., mouse on trigger zone)
if (!root.isBarHovered(screenName)) {
barHoverStateChanged(screenName, false);
}
// Debounce: rapid switches (e.g. external monitor ↔ laptop) cause overlapping
// bar load/unload; 80ms delay coalesces them and reduces QV4 incubation races
root._pendingWorkspaceScreen = screenName;
workspaceDebounceTimer.restart();
}
}