diff --git a/shell/services/AppLibrary.qml b/shell/services/AppLibrary.qml index 317af1e8..738529de 100644 --- a/shell/services/AppLibrary.qml +++ b/shell/services/AppLibrary.qml @@ -187,9 +187,13 @@ Item { property string text: "" } + // Both scans must run in non-login shells. A login shell sources the user's + // profile, and tools like mise touch ~/.local/share on activation — a + // directory the desktop-entry watcher monitors — so every scan would + // trigger the next one, pinning a core at idle. Process { id: hiddenEntryScan - command: ["bash", "-lc", root.hiddenEntryScanCommand()] + command: ["bash", "-c", root.hiddenEntryScanCommand()] stdout: SplitParser { onRead: function(line) { hiddenEntryOutput.text += line + "\n" } } onStarted: hiddenEntryOutput.text = "" onExited: root.loadDesktopHiddenEntries(hiddenEntryOutput.text) @@ -197,7 +201,7 @@ Item { Process { id: iconIndexScan - command: ["bash", "-lc", root.iconIndexScanCommand()] + command: ["bash", "-c", root.iconIndexScanCommand()] stdout: SplitParser { onRead: function(line) { root.indexIconLine(line) } } onStarted: root.pendingIconIndex = ({}) // Swapping the property re-evaluates every iconSource() binding, so diff --git a/test/shell.d/app-search-test.sh b/test/shell.d/app-search-test.sh index 06012221..d0b6a3d1 100644 --- a/test/shell.d/app-search-test.sh +++ b/test/shell.d/app-search-test.sh @@ -114,6 +114,13 @@ assert( 'app library fallback icon index includes device icons' ) +assert( + appLibraryQml.includes('command: ["bash", "-c", root.hiddenEntryScanCommand()]') && + appLibraryQml.includes('command: ["bash", "-c", root.iconIndexScanCommand()]') && + !appLibraryQml.includes('"-lc"'), + 'app library scans avoid login shells whose profile activation retriggers the desktop-entry watcher' +) + assert( /if \(active === "apps"\) \{[\s\S]*?rows\.sort\(function\(a, b\)/.test(menuQml), 'apps menu enforces alphabetical display order after provider refreshes'