Skip to content

Commit ea051bd

Browse files
committed
fix(thermal): eliminate async race condition in modal tab routing
- PopoutService: replace Qt.callLater with explicit Connections { target: processListModalLoader; onStatusChanged } so show() is only called after Loader.Ready, not just after setActive(true). Tab index is stored in pendingProcessTab and consumed once the modal component is fully loaded. - ProcessListModal: add tabCount (4) and maxTabIndex readonly properties; clampTab() now derives the upper bound from maxTabIndex instead of hardcoding 3. nextTab()/previousTab() also use tabCount. - ProcessListModal.show(): restore sort state by calling DgopService.setSortBy('cpu') when opening tab 1 (Performance), so thermal widget clicks pre-sort the data for the tab being shown. - Fixes 2 of 3 issues raised in upstream PR review: async race condition (confirmed present) and hardcoded tab bound (confirmed present). Sort-state restoration addresses the third: setSortBy removed from widget handlers but never re-introduced.
1 parent 36fcf6b commit ea051bd

2 files changed

Lines changed: 33 additions & 5 deletions

File tree

quickshell/Modals/ProcessListModal.qml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ FloatingWindow {
1313

1414
property bool disablePopupTransparency: true
1515
property int currentTab: 0
16+
// Number of tabs in the tab bar — derived from the tab model array.
17+
// Using array literal length (4) as a constant property; matches the
18+
// inline Repeater model so the bound stays correct if tabs are added.
19+
readonly property int tabCount: 4
20+
readonly property int maxTabIndex: tabCount - 1
1621
property string searchText: ""
1722
property string expandedPid: ""
1823
property string processFilter: "all"
@@ -24,7 +29,7 @@ FloatingWindow {
2429
function clampTab(tabIndex) {
2530
if (tabIndex === undefined || tabIndex === null)
2631
return currentTab;
27-
return Math.max(0, Math.min(3, tabIndex));
32+
return Math.max(0, Math.min(maxTabIndex, tabIndex));
2833
}
2934

3035
function show(tabIndex) {
@@ -33,6 +38,13 @@ FloatingWindow {
3338
return;
3439
}
3540
currentTab = clampTab(tabIndex);
41+
// Restore sort state when navigating to Performance tab (tab 1).
42+
// CpuMonitor and RamMonitor call setSortBy themselves; routing here
43+
// from a thermal widget should also set the sort so the data is
44+
// pre-sorted for the tab being opened.
45+
if (currentTab === 1) {
46+
DgopService.setSortBy("cpu");
47+
}
3648
visible = true;
3749
}
3850

@@ -91,11 +103,11 @@ FloatingWindow {
91103
}
92104

93105
function nextTab() {
94-
currentTab = (currentTab + 1) % 4;
106+
currentTab = (currentTab + 1) % tabCount;
95107
}
96108

97109
function previousTab() {
98-
currentTab = (currentTab - 1 + 4) % 4;
110+
currentTab = (currentTab - 1 + tabCount) % tabCount;
99111
}
100112

101113
objectName: "processListModal"

quickshell/Services/PopoutService.qml

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ Singleton {
3939
property var powerMenuModal: null
4040
property var processListModal: null
4141
property var processListModalLoader: null
42+
// Pending tab index for async Loader path — consumed by Connections when modal loads
43+
property int pendingProcessTab: -1
4244
property var colorPickerModal: null
4345
property var notificationModal: null
4446
property var wifiPasswordModal: null
@@ -763,8 +765,8 @@ Singleton {
763765
if (processListModal) {
764766
processListModal.show(tabIndex);
765767
} else if (processListModalLoader) {
768+
pendingProcessTab = (tabIndex !== undefined && tabIndex !== null) ? tabIndex : -1;
766769
processListModalLoader.active = true;
767-
Qt.callLater(() => processListModal?.show(tabIndex));
768770
}
769771
}
770772

@@ -783,8 +785,22 @@ Singleton {
783785
if (processListModal) {
784786
processListModal.toggle(tabIndex);
785787
} else if (processListModalLoader) {
788+
pendingProcessTab = (tabIndex !== undefined && tabIndex !== null) ? tabIndex : -1;
786789
processListModalLoader.active = true;
787-
Qt.callLater(() => processListModal?.show(tabIndex));
790+
}
791+
}
792+
793+
// Reactive async path: when Loader finishes loading, show modal at pending tab.
794+
// Avoids Qt.callLater race condition where the lambda fires before modal is ready.
795+
Connections {
796+
target: processListModalLoader
797+
function onStatusChanged() {
798+
if (!processListModalLoader)
799+
return;
800+
if (processListModalLoader.status === Loader.Ready && pendingProcessTab !== -1) {
801+
processListModal?.show(pendingProcessTab);
802+
pendingProcessTab = -1;
803+
}
788804
}
789805
}
790806

0 commit comments

Comments
 (0)