mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
chore(merge): bar autohide + hyprland fixes
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -72,33 +72,8 @@ Item {
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
asynchronous: false
|
||||
|
||||
// Deferred activation to prevent re-entrant incubation crash:
|
||||
// When ListModel.append() creates this delegate, the Repeater is mid-incubation.
|
||||
// If this Loader activates synchronously (asynchronous: false) during delegate
|
||||
// finalization, it triggers nested QQmlIncubatorPrivate::incubate which corrupts
|
||||
// the V4 heap (SIGSEGV in QV4::Object::insertMember).
|
||||
// Deferring to the next event loop iteration breaks the nesting.
|
||||
property bool _ready: false
|
||||
active: _ready && root.checkWidgetExists() && (root.reloadCounter >= 0)
|
||||
|
||||
Timer {
|
||||
id: activateTimer
|
||||
interval: 0
|
||||
onTriggered: loader._ready = true
|
||||
}
|
||||
|
||||
Component.onCompleted: activateTimer.start()
|
||||
|
||||
// Reset _ready when reloadCounter changes to force a deferred re-activation
|
||||
Connections {
|
||||
target: root
|
||||
function onReloadCounterChanged() {
|
||||
loader._ready = false;
|
||||
activateTimer.restart();
|
||||
}
|
||||
}
|
||||
asynchronous: true
|
||||
active: root.checkWidgetExists() && (root.reloadCounter >= 0)
|
||||
|
||||
sourceComponent: {
|
||||
// Depend on reloadCounter to force re-fetch of component
|
||||
|
||||
@@ -50,7 +50,7 @@ NIconButton {
|
||||
// If using distro logo, don't use theme icon.
|
||||
icon: (customIconPath === "" && !useDistroLogo) ? customIcon : ""
|
||||
tooltipText: {
|
||||
if (PanelService.getPanel("controlCenterPanel", screen)?.isPanelOpen) {
|
||||
if (!screen || PanelService.getPanel("controlCenterPanel", screen)?.isPanelOpen) {
|
||||
return "";
|
||||
} else {
|
||||
return I18n.tr("tooltips.open-control-center");
|
||||
|
||||
@@ -408,7 +408,7 @@ Item {
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
if ((isVertical || scrollingMode === "never") && !PanelService.getPanel("mediaPlayerPanel", screen)?.isPanelOpen) {
|
||||
if (screen && (isVertical || scrollingMode === "never") && !PanelService.getPanel("mediaPlayerPanel", screen)?.isPanelOpen) {
|
||||
TooltipService.show(root, title, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ Item {
|
||||
|
||||
function onVolumeAtMaximum() {
|
||||
if (!firstVolumeReceived) {
|
||||
firstVolumeReceived = true;
|
||||
firstVolumeReceived = true;
|
||||
} else {
|
||||
// Hide any tooltip while the pill is visible / being updated
|
||||
TooltipService.hide();
|
||||
@@ -87,7 +87,7 @@ Item {
|
||||
|
||||
function onVolumeAtMinimum() {
|
||||
if (!firstVolumeReceived) {
|
||||
firstVolumeReceived = true;
|
||||
firstVolumeReceived = true;
|
||||
} else {
|
||||
// Hide any tooltip while the pill is visible / being updated
|
||||
TooltipService.hide();
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user