Launch apps in their own scope instead of the compositor's cgroup (#6541)

* Launch apps in their own scope instead of the compositor's cgroup

The launcher ran desktop entries through gtk-launch, so the app inherited
quickshell's cgroup, which belongs to wayland-wm@hyprland.desktop.service.
A kernel OOM kill there fails the compositor unit and tears down the whole
session, dropping the user at SDDM with every window lost. A single runaway
app took the desktop down three times in one afternoon.

Route launches through uwsm-app so each app gets its own scope under
app-graphical.slice. A runaway app now fails its own scope and the session
keeps running.

The post-install launches had the same inheritance bug in a milder form,
where the app landed in the installer terminal's scope and died with it.
0aedef58 patched that with setsid, which detaches the session but leaves
cgroup membership behind. A scope fixes it properly.

* Detach post-install app launches

* Preserve desktop entry launch compatibility

---------

Co-authored-by: David Heinemeier Hansson <david@hey.com>
This commit is contained in:
Diogo Ferreira
2026-08-04 12:16:54 -05:00
committed by GitHub
co-authored by David Heinemeier Hansson
parent fe55ac264d
commit 40f92eabdf
9 changed files with 118 additions and 14 deletions
+6 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
# omarchy:summary=Install a packaged app and gtk-launch it once it finishes
# omarchy:summary=Install a packaged app and launch it once it finishes
# omarchy:args=<display-name> <packages> <desktop-id>
# omarchy:examples=omarchy install and launch Cursor cursor-bin cursor
@@ -13,5 +13,9 @@ if [[ -z $name || -z $packages || -z $desktop_id ]]; then
exit 1
fi
printf -v install_message '%q' "Installing ${name}..."
printf -v desktop_id_arg '%q' "$desktop_id"
# The subshell keeps & from backgrounding the package installation too.
exec omarchy-launch-floating-terminal-with-presentation \
"echo 'Installing ${name}...'; omarchy-pkg-add ${packages} && setsid gtk-launch ${desktop_id}"
"echo ${install_message}; omarchy-pkg-add ${packages} && (setsid uwsm-app -- gtk-launch ${desktop_id_arg} >/dev/null 2>&1 &)"
+1 -1
View File
@@ -6,4 +6,4 @@ echo "Installing Emacs..."
omarchy-pkg-aur-add omarchy-emacs && omarchy-install-emacs
# emacsclient opens a frame on the running daemon, not a second Emacs
setsid gtk-launch emacsclient
setsid uwsm-app -- gtk-launch emacsclient >/dev/null 2>&1 &
+1 -1
View File
@@ -26,4 +26,4 @@ printf '{\n "update.mode": "none"\n}\n' > ~/.config/Code/User/settings.json
# Apply Omarchy theme to VSCode
omarchy-theme-set-vscode
setsid gtk-launch code
setsid uwsm-app -- gtk-launch code >/dev/null 2>&1 &
+1 -1
View File
@@ -8,4 +8,4 @@ omarchy-pkg-add zed omazed
# Apply Omarchy theme to Zed
omazed setup
setsid gtk-launch dev.zed.Zed
setsid uwsm-app -- gtk-launch dev.zed.Zed >/dev/null 2>&1 &
+1 -1
View File
@@ -9,4 +9,4 @@ echo "Installing Heroic Games Launcher..."
omarchy-pkg-add heroic-games-launcher-bin
omarchy-install-gaming-gpu-lib32
setsid gtk-launch heroic >/dev/null 2>&1 &
setsid uwsm-app -- gtk-launch heroic >/dev/null 2>&1 &
+1 -1
View File
@@ -12,4 +12,4 @@ omarchy-install-gaming-gpu-lib32
echo ""
echo "Steam will start automatically now. This might take a while..."
setsid gtk-launch steam >/dev/null 2>&1 &
setsid uwsm-app -- gtk-launch steam >/dev/null 2>&1 &
+5 -4
View File
@@ -78,10 +78,11 @@ Item {
var id = String(desktopId || "")
if (!id) return
root.beginLaunchFeedback(name)
// Pass the file name with its extension: gtk-launch only appends ".desktop"
// when the argument doesn't already end with it, so ids that themselves end
// in ".desktop" (e.g. org.telegram.desktop) would otherwise never resolve.
Util.execDetached("gtk-launch " + Util.shellQuote(id + ".desktop"))
// Start gtk-launch inside a scope under app-graphical.slice so apps do not
// inherit wayland-wm@.service. Keeping gtk-launch as the desktop-entry
// resolver supports IDs with spaces and entries that UWSM rejects.
// Keep the .desktop suffix or ids like org.telegram.desktop won't resolve.
Util.execDetached("uwsm-app -- gtk-launch " + Util.shellQuote(id + ".desktop"))
}
function remove(desktopId, name) {
+3 -3
View File
@@ -99,9 +99,9 @@ assert(
)
assert(
/function launch\(desktopId, name\) \{[\s\S]*?gtk-launch[\s\S]*?\n \}/.test(appLibraryQml) &&
appLibraryQml.includes('Util.execDetached("gtk-launch "'),
'app library runs desktop entry launch through the shell'
/function launch\(desktopId, name\) \{[\s\S]*?uwsm-app[\s\S]*?\n \}/.test(appLibraryQml) &&
appLibraryQml.includes('Util.execDetached("uwsm-app -- gtk-launch "'),
'app library launches desktop entries through gtk-launch in their own scope'
)
assert(
+99
View File
@@ -0,0 +1,99 @@
#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
mock_bin="$test_tmp/bin"
test_home="$test_tmp/home"
mkdir -p "$mock_bin" "$test_home"
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
#!/bin/bash
printf 'pkg:%s\n' "$*" >>"$OMARCHY_TEST_LOG"
exit "${OMARCHY_TEST_PKG_STATUS:-0}"
SH
for command in omarchy-pkg-aur-add omarchy-install-emacs omazed omarchy-theme-set-vscode omarchy-install-gaming-gpu-lib32; do
cat >"$mock_bin/$command" <<'SH'
#!/bin/bash
exit 0
SH
done
cat >"$mock_bin/setsid" <<'SH'
#!/bin/bash
printf 'launch:%s\n' "$*" >>"$OMARCHY_TEST_LOG"
SH
cat >"$mock_bin/omarchy-launch-floating-terminal-with-presentation" <<'SH'
#!/bin/bash
printf '%s\n' "$1" >"$OMARCHY_TEST_PRESENTATION"
SH
chmod +x "$mock_bin"/*
export HOME="$test_home"
export OMARCHY_TEST_LOG="$test_tmp/launch.log"
export OMARCHY_TEST_PRESENTATION="$test_tmp/presentation"
export PATH="$mock_bin:$PATH"
wait_for_launch() {
local expected="$1"
for ((attempt = 0; attempt < 100; attempt++)); do
grep -Fxq "$expected" "$OMARCHY_TEST_LOG" && return 0
sleep 0.01
done
return 1
}
assert_detached_installer_launch() {
local script="$1"
local desktop_id="$2"
: >"$OMARCHY_TEST_LOG"
bash "$ROOT/bin/$script"
wait_for_launch "launch:uwsm-app -- gtk-launch $desktop_id" ||
fail "$script launches its desktop entry through gtk-launch in a UWSM scope"
grep -Fqx "setsid uwsm-app -- gtk-launch $desktop_id >/dev/null 2>&1 &" "$ROOT/bin/$script" ||
fail "$script detaches its scoped desktop-entry launch"
pass "$script detaches its scoped desktop-entry launch"
}
assert_detached_installer_launch omarchy-install-editor-emacs emacsclient
assert_detached_installer_launch omarchy-install-editor-vscode code
assert_detached_installer_launch omarchy-install-editor-zed dev.zed.Zed
assert_detached_installer_launch omarchy-install-gaming-heroic heroic
assert_detached_installer_launch omarchy-install-gaming-steam steam
bash "$ROOT/bin/omarchy-install-and-launch" "Example App" "alpha beta" "Disk Usage"
presentation_command=$(<"$OMARCHY_TEST_PRESENTATION")
[[ $presentation_command == *'echo Installing\ Example\ App...;'* ]] ||
fail "generic installer shell-quotes the display name" "$presentation_command"
[[ $presentation_command == *'omarchy-pkg-add alpha beta && (setsid uwsm-app -- gtk-launch Disk\ Usage >/dev/null 2>&1 &)'* ]] ||
fail "generic installer waits for packages and detaches only the scoped launch" "$presentation_command"
pass "generic installer waits for packages and detaches only the scoped launch"
: >"$OMARCHY_TEST_LOG"
bash -c "$presentation_command"
grep -Fxq 'pkg:alpha beta' "$OMARCHY_TEST_LOG" ||
fail "generic installer passes every package to the package helper"
wait_for_launch 'launch:uwsm-app -- gtk-launch Disk Usage' ||
fail "generic installer preserves a desktop ID containing spaces"
pass "generic installer preserves a desktop ID containing spaces"
: >"$OMARCHY_TEST_LOG"
if OMARCHY_TEST_PKG_STATUS=1 bash -c "$presentation_command"; then
fail "generic installer propagates package installation failure"
fi
if grep -q '^launch:' "$OMARCHY_TEST_LOG"; then
fail "generic installer does not launch after package installation failure"
fi
pass "generic installer does not launch after package installation failure"