From 9754326f1d61909c8db8d5663c73c7c149999ccb Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Mon, 28 Sep 2026 11:33:56 +0100 Subject: [PATCH] Stop the native portal with the graphical session --- docs/installation.md | 4 +- ...desktop.impl.portal.desktop.ferese.service | 1 + .../systemd/xdg-desktop-portal-ferese.service | 9 +++ scripts/install-session.sh | 13 ++++- scripts/tests/test_portal_install.py | 55 +++++++++++++++++++ 5 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 packaging/systemd/xdg-desktop-portal-ferese.service create mode 100644 scripts/tests/test_portal_install.py diff --git a/docs/installation.md b/docs/installation.md index e9c989f..980a1d8 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -17,7 +17,9 @@ Settings, command-line tools, locker, polkit agent, and ScreenCast portal togeth packages or enable background services at boot. On systemd systems, the installed session helper activates `ferese-session.target` after exporting the compositor's Wayland display, and stops it when the shell exits. This keeps -`graphical-session.target` active so desktop portals can start. Nested previews +`graphical-session.target` active so desktop portals can start. The native portal +is D-Bus activated and supervised by systemd; it stops with the session so a +previous release cannot remain running after logout. Nested previews do not alter the host's activation environment or session targets. ### Fedora diff --git a/packaging/portal/org.freedesktop.impl.portal.desktop.ferese.service b/packaging/portal/org.freedesktop.impl.portal.desktop.ferese.service index b4bf12c..087b3b4 100644 --- a/packaging/portal/org.freedesktop.impl.portal.desktop.ferese.service +++ b/packaging/portal/org.freedesktop.impl.portal.desktop.ferese.service @@ -1,3 +1,4 @@ [D-BUS Service] Name=org.freedesktop.impl.portal.desktop.ferese Exec=/usr/local/lib/ferese/current/xdg-desktop-portal-ferese +SystemdService=xdg-desktop-portal-ferese.service diff --git a/packaging/systemd/xdg-desktop-portal-ferese.service b/packaging/systemd/xdg-desktop-portal-ferese.service new file mode 100644 index 0000000..645b984 --- /dev/null +++ b/packaging/systemd/xdg-desktop-portal-ferese.service @@ -0,0 +1,9 @@ +[Unit] +Description=Ferese desktop portal +PartOf=ferese-session.target graphical-session.target +After=ferese-session.target + +[Service] +Type=dbus +BusName=org.freedesktop.impl.portal.desktop.ferese +ExecStart=/usr/local/lib/ferese/current/xdg-desktop-portal-ferese diff --git a/scripts/install-session.sh b/scripts/install-session.sh index e922536..f5e5127 100644 --- a/scripts/install-session.sh +++ b/scripts/install-session.sh @@ -70,7 +70,17 @@ for entry in \ done service=/usr/local/share/dbus-1/services/org.freedesktop.impl.portal.desktop.ferese.service if [[ -e $service ]] && ! cmp -s "$repo_dir/packaging/portal/$(basename "$service")" "$service"; then - echo "Unmanaged portal service exists: $service" >&2; exit 1 + # Upgrade the exact activation file shipped before systemd supervision. + if ! cmp -s <(printf '%s\n' '[D-BUS Service]' \ + 'Name=org.freedesktop.impl.portal.desktop.ferese' \ + 'Exec=/usr/local/lib/ferese/current/xdg-desktop-portal-ferese') "$service"; then + echo "Unmanaged portal service exists: $service" >&2; exit 1 + fi +fi + +portal_unit=/usr/local/lib/systemd/user/xdg-desktop-portal-ferese.service +if [[ -e $portal_unit ]] && ! cmp -s "$repo_dir/packaging/systemd/xdg-desktop-portal-ferese.service" "$portal_unit"; then + echo "Unmanaged portal unit exists: $portal_unit" >&2; exit 1 fi session_target=/usr/local/lib/systemd/user/ferese-session.target @@ -91,6 +101,7 @@ done install -m 0755 -- "$repo_dir/packaging/ferese-session" "$release_dir/ferese-session" install -m 0755 -- "$repo_dir/packaging/ferese-session-shell" "$release_dir/ferese-session-shell" install -D -m 0644 -- "$repo_dir/packaging/systemd/ferese-session.target" "$session_target" +install -D -m 0644 -- "$repo_dir/packaging/systemd/xdg-desktop-portal-ferese.service" "$portal_unit" install -m 0755 -- "$repo_dir/packaging/ferese-screenshot" "$release_dir/ferese-screenshot" install -m 0644 -- "$repo_dir/packaging/config.kdl" "$release_dir/config.example.kdl" install -D -m 0644 -- "$repo_dir/assets/fonts/Comfortaa-LICENSE.txt" "$release_dir/licenses/Comfortaa-LICENSE.txt" diff --git a/scripts/tests/test_portal_install.py b/scripts/tests/test_portal_install.py new file mode 100644 index 0000000..52906a4 --- /dev/null +++ b/scripts/tests/test_portal_install.py @@ -0,0 +1,55 @@ +"""Exercise portal upgrade preflight against temporary installation files.""" +from pathlib import Path +import subprocess +import tempfile +import unittest + +REPO = Path(__file__).resolve().parents[2] +LEGACY = ('[D-BUS Service]\n' + 'Name=org.freedesktop.impl.portal.desktop.ferese\n' + 'Exec=/usr/local/lib/ferese/current/xdg-desktop-portal-ferese\n') + + +class PortalInstallTest(unittest.TestCase): + def preflight(self, service=None, unit=None): + script = (REPO / 'scripts/install-session.sh').read_text() + start = script.index('service=/usr/local/share/dbus-1/services/') + script = script[start:script.index('session_target=', start)] + with tempfile.TemporaryDirectory() as directory: + root = Path(directory) + if service is not None: + (root / 'activation.service').write_text(service) + if unit is not None: + (root / 'portal.service').write_text(unit) + script = script.replace( + 'service=/usr/local/share/dbus-1/services/org.freedesktop.impl.portal.desktop.ferese.service', + 'service="$TEST_ROOT/activation.service"') + script = script.replace('$(basename "$service")', + 'org.freedesktop.impl.portal.desktop.ferese.service') + script = script.replace( + 'portal_unit=/usr/local/lib/systemd/user/xdg-desktop-portal-ferese.service', + 'portal_unit="$TEST_ROOT/portal.service"') + return subprocess.run(['bash', '-eu', '-c', script], + env={'repo_dir': str(REPO), 'TEST_ROOT': directory}, + capture_output=True, text=True) + + def test_accepts_fresh_install_and_previous_activation_file(self): + self.assertEqual(self.preflight().returncode, 0) + self.assertEqual(self.preflight(LEGACY).returncode, 0) + + def test_accepts_current_managed_files(self): + service = (REPO / 'packaging/portal/org.freedesktop.impl.portal.desktop.ferese.service').read_text() + unit = (REPO / 'packaging/systemd/xdg-desktop-portal-ferese.service').read_text() + self.assertEqual(self.preflight(service, unit).returncode, 0) + + def test_preserves_modified_activation_and_systemd_files(self): + result = self.preflight(LEGACY.replace('/usr/local/lib/ferese/current/', '/custom/')) + self.assertNotEqual(result.returncode, 0) + self.assertIn('Unmanaged portal service', result.stderr) + result = self.preflight(LEGACY, '[Service]\nExecStart=/custom/portal\n') + self.assertNotEqual(result.returncode, 0) + self.assertIn('Unmanaged portal unit', result.stderr) + + +if __name__ == '__main__': + unittest.main()