[neon/backports-noble/xdg-desktop-portal-noble/Neon/release] debian: new release, manually merge in salsa debian/latest

Jonathan Riddell null at kde.org
Thu Oct 31 16:15:38 GMT 2024


Git commit 29cd4813f437e91eedaf97a05ab9828ded043690 by Jonathan Riddell.
Committed on 31/10/2024 at 16:10.
Pushed by jriddell into branch 'Neon/release'.

new release, manually merge in salsa debian/latest

M  +29   -141  debian/changelog
M  +20   -8    debian/control
M  +28   -14   debian/copyright
M  +1    -2    debian/gbp.conf
A  +38   -0    debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
M  +3    -1    debian/patches/series
D  +0    -1758 debian/patches/webextensions-portal.patch
A  +31   -0    debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
A  +46   -0    debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
M  +14   -1    debian/rules
M  +0    -4    debian/salsa-ci.yml
M  +5    -4    debian/watch
M  +2    -2    debian/xdg-desktop-portal-dev.doc-base
A  +1    -0    debian/xdg-desktop-portal-dev.docs
M  +0    -2    debian/xdg-desktop-portal-dev.install
A  +1    -0    debian/xdg-desktop-portal-dev.links
D  +0    -2    debian/xdg-desktop-portal.lintian-overrides

https://invent.kde.org/neon/backports-noble/xdg-desktop-portal-noble/-/commit/29cd4813f437e91eedaf97a05ab9828ded043690

diff --git a/debian/changelog b/debian/changelog
index af5e40f..bbeb9e4 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,11 +1,33 @@
-xdg-desktop-portal (1.18.4-1ubuntu2) noble; urgency=medium
+xdg-desktop-portal (1.19.0+ds-1) experimental; urgency=medium
 
-  * Merge with Debian (LP: #2062394). Remaining change:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch to add a portal for managing WebExtensions native messaging
-      servers
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 18 Apr 2024 17:00:47 -0400
+  * New upstream development release
+  * d/copyright: Update
+  * Repack tarball to exclude vendored Inter Variable font from
+    documentation
+  * d/p/debian/doc-Use-system-copy-of-Inter-Variable-font.patch:
+    Add a patch to avoid using the vendored Inter Variable font, which
+    we remove
+  * d/copyright, d/watch: Update for exclusion of vendored web font
+  * Remove obsolete Lintian override for #1031037, fixed in
+    Lintian 2.117.0
+  * d/control, d/x-d-p-dev.docs, d/x-d-p-dev.doc-base:
+    Build HTML documentation using Sphinx; enable dh_sphinxdoc
+  * d/rules: Update Meson options.
+    sandboxed-image-validation is now a feature rather than a boolean.
+  * d/p/xdp_validate_icon-Assign-argument-indices-automatically.patch,
+    d/p/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch,
+    d/rules:
+    Disable sandboxing of icon validation during build-time testing.
+    Some buildds build in a chroot, and bubblewrap can't work in that
+    environment.
+  * d/control: Add librsvg2-common to Recommends, Build-Depends,
+    test Depends. This is needed for SVG icon validation.
+  * d/control: Explicitly build-depend on bubblewrap
+  * d/control, d/rules: Only build documentation in arch-indep builds
+  * d/rules: Disable man pages under nodoc build profile
+  * Standards-Version: 4.7.0 (no changes required)
+
+ -- Simon McVittie <smcv at debian.org>  Wed, 30 Oct 2024 19:46:16 +0000
 
 xdg-desktop-portal (1.18.4-1) unstable; urgency=medium
 
@@ -18,16 +40,6 @@ xdg-desktop-portal (1.18.4-1) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Thu, 18 Apr 2024 18:58:16 +0100
 
-xdg-desktop-portal (1.18.3-1ubuntu1) noble; urgency=medium
-
-  * Merge with Debian. Remaining change:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 11 Apr 2024 18:21:31 -0400
-
 xdg-desktop-portal (1.18.3-1) unstable; urgency=medium
 
   * Team upload
@@ -35,16 +47,6 @@ xdg-desktop-portal (1.18.3-1) unstable; urgency=medium
 
  -- Jeremy Bícha <jbicha at ubuntu.com>  Thu, 04 Apr 2024 10:53:28 -0400
 
-xdg-desktop-portal (1.18.2-1ubuntu1) noble; urgency=medium
-
-  * Merge with Debian (LP: #2038110). Remaining change:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 27 Nov 2023 13:10:20 -0500
-
 xdg-desktop-portal (1.18.2-1) unstable; urgency=medium
 
   * Team upload
@@ -64,38 +66,12 @@ xdg-desktop-portal (1.18.1-1) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Thu, 26 Oct 2023 19:28:38 +0100
 
-xdg-desktop-portal (1.18.0-1ubuntu1) mantic; urgency=medium
-
-  * Merge with Debian (LP: #2038110). Remaining change:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-  * Dropped change:
-    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
-      to Ubuntu 20.04 LTS or 18.04 LTS
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 02 Oct 2023 12:21:53 -0400
-
 xdg-desktop-portal (1.18.0-1) unstable; urgency=medium
 
   * New upstream stable release
 
  -- Simon McVittie <smcv at debian.org>  Tue, 19 Sep 2023 12:01:57 +0100
 
-xdg-desktop-portal (1.17.2-1ubuntu1) mantic; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
-      to Ubuntu 20.04 LTS or 18.04 LTS
-  * Update webextension portal patch with latest version proposed upstream
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Tue, 05 Sep 2023 13:08:18 -0400
-
 xdg-desktop-portal (1.17.2-1) unstable; urgency=medium
 
   * New upstream release
@@ -130,18 +106,6 @@ xdg-desktop-portal (1.17.0-1) experimental; urgency=medium
 
  -- Jeremy Bícha <jbicha at ubuntu.com>  Mon, 21 Aug 2023 16:33:43 -0400
 
-xdg-desktop-portal (1.16.0-3ubuntu1) mantic; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-    - Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
-      to Ubuntu 20.04 LTS or 18.04 LTS
-
- -- Jeremy Bícha <jbicha at ubuntu.com>  Fri, 18 Aug 2023 09:07:20 -0400
-
 xdg-desktop-portal (1.16.0-3) unstable; urgency=medium
 
   * d/patches: Update to upstream 1.16 branch commit 1.16.0-17-g2a219279
@@ -157,19 +121,6 @@ xdg-desktop-portal (1.16.0-3) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Sat, 05 Aug 2023 15:33:04 +0100
 
-xdg-desktop-portal (1.16.0-2ubuntu1) lunar; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-  * d/p/webextensions-portal.patch: updated
-  * Keep alternative dependency to libgdk-pixbuf2.0-dev for easier backports
-    to Ubuntu 20.04 LTS or 18.04 LTS
-
- -- Nathan Pratta Teodosio <nathan.teodosio at canonical.com>  Wed, 25 Jan 2023 15:33:03 -0300
-
 xdg-desktop-portal (1.16.0-2) unstable; urgency=medium
 
   * d/patches: Add post-release bug fixes from upstream
@@ -181,17 +132,6 @@ xdg-desktop-portal (1.16.0-2) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Tue, 10 Jan 2023 11:31:45 +0000
 
-xdg-desktop-portal (1.16.0-1ubuntu1) lunar; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-  * Update webextensions-portal.patch with latest proposed version
-
- -- Jeremy Bicha <jbicha at ubuntu.com>  Thu, 15 Dec 2022 10:39:43 -0500
-
 xdg-desktop-portal (1.16.0-1) unstable; urgency=medium
 
   * New upstream release
@@ -238,17 +178,6 @@ xdg-desktop-portal (1.15.0-2) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Thu, 15 Sep 2022 19:20:27 +0100
 
-xdg-desktop-portal (1.15.0-1ubuntu1) kinetic; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-  * Update webextensions-portal.patch with latest proposed version
-
- -- Jeremy Bicha <jbicha at ubuntu.com>  Mon, 15 Aug 2022 06:59:02 -0400
-
 xdg-desktop-portal (1.15.0-1) experimental; urgency=medium
 
   * New upstream development release
@@ -275,16 +204,6 @@ xdg-desktop-portal (1.14.5-1) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Tue, 19 Jul 2022 18:58:07 +0100
 
-xdg-desktop-portal (1.14.4-1ubuntu1) kinetic; urgency=medium
-
-  * Merge from Debian. Remaining changes:
-    - Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-      distro-patch (add a portal for managing WebExtensions native messaging
-      servers, LP: #1968215)
-      + debian/patches/webextensions-portal.patch
-
- -- Olivier Tilloy <olivier.tilloy at canonical.com>  Mon, 13 Jun 2022 11:21:47 +0200
-
 xdg-desktop-portal (1.14.4-1) unstable; urgency=medium
 
   * New upstream stable release
@@ -297,37 +216,6 @@ xdg-desktop-portal (1.14.3-1) unstable; urgency=medium
 
  -- Simon McVittie <smcv at debian.org>  Fri, 15 Apr 2022 16:30:43 +0100
 
-xdg-desktop-portal (1.14.3-0ubuntu3) kinetic; urgency=medium
-
-  * Update the native messaging portal patch to pick up a new commit
-    - debian/patches/webextensions-portal.patch
-
- -- Olivier Tilloy <olivier.tilloy at canonical.com>  Wed, 11 May 2022 11:06:32 +0200
-
-xdg-desktop-portal (1.14.3-0ubuntu2) jammy; urgency=medium
-
-  * New upstream stable release
-    - Fixes crash with Teamviewer's experimental Wayland support
-      (LP: #1966945)
-
- -- Jeremy Bicha <jbicha at ubuntu.com>  Fri, 15 Apr 2022 15:17:26 -0400
-
-xdg-desktop-portal (1.14.2-1ubuntu2) jammy; urgency=medium
-
-  * Update the native messaging portal patch to pick up new commits
-    - debian/patches/webextensions-portal.patch
-
- -- Olivier Tilloy <olivier.tilloy at canonical.com>  Mon, 11 Apr 2022 18:47:05 +0200
-
-xdg-desktop-portal (1.14.2-1ubuntu1) jammy; urgency=medium
-
-  * Import https://github.com/flatpak/xdg-desktop-portal/pull/705 as a
-    distro-patch (add a portal for managing WebExtensions native messaging
-    servers, LP: #1968215)
-    - debian/patches/webextensions-portal.patch
-
- -- Olivier Tilloy <olivier.tilloy at canonical.com>  Fri, 08 Apr 2022 11:16:45 +0200
-
 xdg-desktop-portal (1.14.2-1) unstable; urgency=medium
 
   * New upstream release
diff --git a/debian/control b/debian/control
index 7c5afbb..9f7e7ac 100644
--- a/debian/control
+++ b/debian/control
@@ -1,11 +1,11 @@
 Source: xdg-desktop-portal
 Section: admin
 Priority: optional
-Maintainer: Ubuntu Developers <ubuntu-devel-discuss at lists.ubuntu.com>
-XSBC-Original-Maintainer: Utopia Maintenance Team <pkg-utopia-maintainers at lists.alioth.debian.org>
+Maintainer: Utopia Maintenance Team <pkg-utopia-maintainers at lists.alioth.debian.org>
 Uploaders:
  Simon McVittie <smcv at debian.org>,
 Build-Depends:
+ bubblewrap,
  dbus-daemon,
  debhelper-compat (= 13),
  geoclue-2.0 <!nocheck>,
@@ -19,6 +19,7 @@ Build-Depends:
  libjson-glib-dev,
  libpipewire-0.3-dev,
  libportal-dev (>= 0.3),
+ librsvg2-common <!nocheck>,
  libsystemd-dev,
  meson,
  pipewire <!nocheck>,
@@ -28,14 +29,17 @@ Build-Depends:
  python3-docutils <!nodoc>,
  python3-gi <!nocheck>,
  python3-pytest <!nocheck>,
- xmlto,
+Build-Depends-Indep:
+ dh-sequence-sphinxdoc <!nodoc>,
+ furo <!nodoc>,
+ python3-sphinx <!nodoc>,
+ python3-sphinx-copybutton <!nodoc>,
+ python3-sphinxext-opengraph <!nodoc>,
 Rules-Requires-Root: no
-Standards-Version: 4.6.2
+Standards-Version: 4.7.0
 Homepage: https://github.com/flatpak/xdg-desktop-portal
-XS-Debian-Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git
-XS-Debian-Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portal
-Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git -b ubuntu/master
-Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portaltree/ubuntu/master
+Vcs-Git: https://salsa.debian.org/debian/xdg-desktop-portal.git
+Vcs-Browser: https://salsa.debian.org/debian/xdg-desktop-portal
 
 Package: xdg-desktop-portal
 Architecture: linux-any
@@ -46,6 +50,8 @@ Depends:
  fuse3,
  ${misc:Depends},
  ${shlibs:Depends},
+Recommends:
+ librsvg2-common,
 Description: desktop integration portal for Flatpak and Snap
  xdg-desktop-portal provides a portal frontend service for Flatpak, Snap,
  and possibly other desktop containment/sandboxing frameworks. This service
@@ -67,9 +73,14 @@ Description: desktop integration portal for Flatpak and Snap
 Package: xdg-desktop-portal-dev
 Architecture: all
 Multi-Arch: foreign
+Built-Using:
+ ${sphinxdoc:Built-Using},
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
+ ${sphinxdoc:Depends},
+Recommends:
+ fonts-inter-variable,
 Description: desktop integration portal - development files
  xdg-desktop-portal provides a portal frontend service for Flatpak, Snap,
  and possibly other desktop containment/sandboxing frameworks. This service
@@ -87,6 +98,7 @@ Depends:
  dbus-daemon,
  geoclue-2.0,
  libcap2-bin,
+ librsvg2-common,
  pipewire,
  procps,
  python3,
diff --git a/debian/copyright b/debian/copyright
index 9ec0804..0d55bd6 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,21 +1,26 @@
 Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
 Upstream-Name: xdg-desktop-portal
 Source: https://github.com/flatpak/xdg-desktop-portal/releases
+Files-Excluded: doc/_static/inter.woff2
 
 Files:
  *
 Copyright:
- © 2010 Codethink Limited
- © 2013-2019 Red Hat, Inc
- © 2016 Free Software Foundation, Inc.
- © 2016 Piotr Drag
- © 2016 Aviary.pl
- © 2017 Jan Alexander Steffens
- © 2018-2021 Igalia S.L.
- © 2022 Aleix Pol Gonzalez
- © 2022 Endless OS Foundation, LLC
- © 2022 Georges Basile Stavracas Neto
-License: LGPL-2+
+ 2022 Aleix Pol Gonzalez
+ 2016 Aviary.pl
+ 2010 Codethink Limited
+ 2021 Collabora Ltd.
+ 2021-2022 Endless OS Foundation, LLC
+ 2016 Free Software Foundation, Inc.
+ 2022 Georges Basile Stavracas Neto
+ 2023-2024 GNOME Foundation Inc.
+ 2022 Google LLC
+ 2018-2023 Igalia S.L.
+ 2017 Jan Alexander Steffens
+ 2021-2022 Matthew Leeds
+ 2016 Piotr Drag
+ 2013-2024 Red Hat, Inc
+License: LGPL-2.1+
 
 Files:
  doc/website/*
@@ -23,10 +28,19 @@ Copyright: none claimed
 License: CC0-1.0
 
 Files:
- src/flatpak-instance.*
+ .github/workflows/check-potfiles.sh
 Copyright:
- © 2018 Red Hat, Inc
-License: LGPL-2.1+
+ 2020-2023 Florian Müllner
+ 2024 Corey Berla
+ 2024 Matthijs Velsink
+License: probably-GPL-2
+ This file originated in gnome-shell, from which it was copied via
+ nautilus and gnome-control-center into xdg-desktop-portal, with no
+ explicit license specified. The actual license is unclear, but it's
+ either GPL-2 or LGPL-2.1, with or without the "or any later version"
+ clause. On a Debian system, the relevant licenses can be found in
+ <file:///usr/share/common-licenses/GPL-2> and
+ <file:///usr/share/common-licenses/LGPL-2.1>.
 
 Files:
  debian/*
diff --git a/debian/gbp.conf b/debian/gbp.conf
index 40b834b..1c8402c 100644
--- a/debian/gbp.conf
+++ b/debian/gbp.conf
@@ -1,8 +1,7 @@
 [DEFAULT]
 pristine-tar = True
 compression = xz
-debian-branch = ubuntu/latest
-debian-tag = ubuntu/%(version)s
+debian-branch = debian/latest
 upstream-branch = upstream/latest
 patch-numbers = False
 upstream-vcs-tag = %(version)s
diff --git a/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch b/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
new file mode 100644
index 0000000..510b969
--- /dev/null
+++ b/debian/patches/debian/doc-Use-system-copy-of-Inter-Variable-font.patch
@@ -0,0 +1,38 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Tue, 15 Oct 2024 14:25:07 +0100
+Subject: doc: Use system copy of Inter Variable font
+
+Forwarded: not-needed, Debian-specific
+---
+ doc/_static/xdg.css | 11 +----------
+ 1 file changed, 1 insertion(+), 10 deletions(-)
+
+diff --git a/doc/_static/xdg.css b/doc/_static/xdg.css
+index 59728dd..298b982 100644
+--- a/doc/_static/xdg.css
++++ b/doc/_static/xdg.css
+@@ -6,15 +6,6 @@ https://pypi.org/project/furo/
+ 
+ /* FONTS */
+ 
+- at font-face {
+-  font-family: "Inter var";
+-  font-weight: 100 900;
+-  font-display: swap;
+-  font-style: normal;
+-  font-named-instance: "Regular";
+-  src: url("inter.woff2") format("woff2");
+-}
+-
+ :root {
+   --rounded-corner: 12px;
+   --blue1: rgb(153,193,241);
+@@ -97,7 +88,7 @@ html, body {
+   margin: 0;
+   padding: 0;
+   font-size: 16px;
+-  font-family: "Inter var", sans-serif;
++  font-family: "Inter Variable", "Inter var", sans-serif;
+   font-weight: 400;
+   line-height: 1.6;
+ }
diff --git a/debian/patches/series b/debian/patches/series
index edf4c72..d110aab 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1 +1,3 @@
-webextensions-portal.patch
+xdp_validate_icon-Assign-argument-indices-automatically.patch
+xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
+debian/doc-Use-system-copy-of-Inter-Variable-font.patch
diff --git a/debian/patches/webextensions-portal.patch b/debian/patches/webextensions-portal.patch
deleted file mode 100644
index bb2f277..0000000
--- a/debian/patches/webextensions-portal.patch
+++ /dev/null
@@ -1,1758 +0,0 @@
-From: James Henstridge <james at jamesh.id.au>
-Date: Tue, 1 Feb 2022 20:12:49 +0800
-Subject: webextensions: add a portal for managing WebExtensions native
- messaging servers.
-
-This is intended to provide a way for a confined web browser to start
-native code helpers for their extensions. At present it can start the
-servers installed on the host system. But in future this could be
-extended to cover sandboxed native messaging servers too.
-
-Origin: https://github.com/flatpak/xdg-desktop-portal/pull/705
-Last-Update: 2023-07-06
----
- data/meson.build                                   |   1 +
- data/org.freedesktop.portal.WebExtensions.xml      | 130 ++++
- meson.build                                        |   3 +
- src/meson.build                                    |   1 +
- src/request.c                                      |  12 +
- src/web-extensions.c                               | 719 +++++++++++++++++++++
- src/web-extensions.h                               |  24 +
- src/xdg-desktop-portal.c                           |  11 +
- tests/meson.build                                  |   3 +
- tests/native-messaging-hosts/meson.build           |   6 +
- .../org.example.testing.json                       |   9 +
- tests/test-portals.c                               |   7 +
- tests/web-extensions.c                             | 610 +++++++++++++++++
- tests/web-extensions.h                             |   2 +
- 14 files changed, 1538 insertions(+)
- create mode 100644 data/org.freedesktop.portal.WebExtensions.xml
- create mode 100644 src/web-extensions.c
- create mode 100644 src/web-extensions.h
- create mode 100644 tests/native-messaging-hosts/meson.build
- create mode 100644 tests/native-messaging-hosts/org.example.testing.json
- create mode 100644 tests/web-extensions.c
- create mode 100644 tests/web-extensions.h
-
-diff --git a/data/meson.build b/data/meson.build
-index eea49ad..63ea5fb 100644
---- a/data/meson.build
-+++ b/data/meson.build
-@@ -37,6 +37,7 @@ portal_sources = files(
-   'org.freedesktop.portal.Settings.xml',
-   'org.freedesktop.portal.Trash.xml',
-   'org.freedesktop.portal.Wallpaper.xml',
-+  'org.freedesktop.portal.WebExtensions.xml',
- )
- 
- portal_impl_sources = files(
-diff --git a/data/org.freedesktop.portal.WebExtensions.xml b/data/org.freedesktop.portal.WebExtensions.xml
-new file mode 100644
-index 0000000..e4ce12c
---- /dev/null
-+++ b/data/org.freedesktop.portal.WebExtensions.xml
-@@ -0,0 +1,130 @@
-+<?xml version="1.0"?>
-+<!--
-+ Copyright (C) 2022 Canonical Ltd
-+
-+ This library is free software; you can redistribute it and/or
-+ modify it under the terms of the GNU Lesser General Public
-+ License as published by the Free Software Foundation; either
-+ version 2 of the License, or (at your option) any later version.
-+
-+ This library is distributed in the hope that it will be useful,
-+ but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ Lesser General Public License for more details.
-+
-+ You should have received a copy of the GNU Lesser General Public
-+ License along with this library. If not, see <http://www.gnu.org/licenses/>.
-+-->
-+
-+<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
-+  <!--
-+      org.freedesktop.portal.WebExtensions:
-+      @short_description: WebExtensions portal
-+
-+      The WebExtensions portal allows sandboxed web browsers to start
-+      native messaging servers installed on the host system.
-+
-+      This documentation describes version 1 of this interface.
-+  -->
-+  <interface name="org.freedesktop.portal.WebExtensions">
-+    <!--
-+        CreateSession:
-+        @options: Vardict with optional further information
-+        @session_handle: Object path for the #org.freedesktop.portal.Session created by this call.
-+
-+        Create a web extensions session. A successfully created
-+        session can at any time be closed using
-+        org.freedesktop.portal.Session::Close, or may at any time be
-+        closed by the portal implementation, which will be signalled
-+        via org.freedesktop.portal.Session::Closed.
-+
-+        Supported keys in the @options vardict include:
-+        <variablelist>
-+          <varlistentry>
-+            <term>session_handle_token s</term>
-+            <listitem><para>
-+              A string that will be used as the last element of the session handle. Must be a valid
-+              object path element. See the #org.freedesktop.portal.Session documentation for
-+              more information about the session handle.
-+            </para></listitem>
-+          </varlistentry>
-+        </variablelist>
-+    -->
-+    <method name="CreateSession">
-+      <arg type="a{sv}" name="options" direction="in"/>
-+      <arg type="o" name="session_handle" direction="out"/>
-+    </method>
-+    <!--
-+        GetManifest:
-+        @session_handle: Object path for the #org.freedesktop.portal.Session object
-+        @name: name of the native messaging server
-+        @extension_or_origin: extension ID or origin URI identifying the extension
-+        @json_manifest: the JSON manifest for the native messaging server
-+
-+        Return the JSON manifest of the native messaging server that
-+        Start would invoke.
-+    -->
-+    <method name="GetManifest">
-+      <arg type="o" name="session_handle" direction="in"/>
-+      <arg type="s" name="name" direction="in"/>
-+      <arg type="s" name="extension_or_origin" direction="in"/>
-+      <arg type="s" name="json_manifest" direction="out"/>
-+    </method>
-+    <!--
-+        Start:
-+        @session_handle: Object path for the #org.freedesktop.portal.Session object
-+        @name: name of the native messaging server
-+        @extension_or_origin: extension ID or origin URI identifying the extension
-+        @options: Vardict with optional further information
-+        @handle: Object path for the #org.freedesktop.portal.Request object representing this call
-+
-+        Start the named native messaging server. The caller must
-+        indicate the requesting web extension (either by extension ID
-+        for Firefox, or origin URI for Chrome), which will be matched
-+        against the server's access control list.
-+
-+        If the server can't be started, or invalid data is provided,
-+        the session will be closed.
-+
-+        Supported keys in the @options vardict include:
-+        <variablelist>
-+          <varlistentry>
-+            <term>handle_token s</term>
-+            <listitem><para>
-+              A string that will be used as the last element of the @handle. Must be a valid
-+              object path element. See the #org.freedesktop.portal.Request documentation for
-+              more information about the @handle.
-+            </para></listitem>
-+          </varlistentry>
-+        </variablelist>
-+    -->
-+    <method name="Start">
-+      <arg type="o" name="session_handle" direction="in"/>
-+      <arg type="s" name="name" direction="in"/>
-+      <arg type="s" name="extension_or_origin" direction="in"/>
-+      <arg type="a{sv}" name="options" direction="in"/>
-+      <arg type="o" name="handle" direction="out"/>
-+    </method>
-+    <!--
-+        GetPipes:
-+        @session_handle: Object path for the #org.freedesktop.portal.Session object
-+        @options: Vardict with optional further information
-+        @stdin: File descriptor representing the server's stdin.
-+        @stdout: File descriptor representing the server's stdout.
-+        @stderr: File descriptor representing the server's stderr.
-+
-+        Retrieve file descriptors for the native messaging server
-+        identified by the session. This method should only be called
-+        after the Start request recveives a successful response.
-+    -->
-+    <method name="GetPipes">
-+      <annotation name="org.gtk.GDBus.C.UnixFD" value="true"/>
-+      <arg type="o" name="session_handle" direction="in"/>
-+      <arg type="a{sv}" name="options" direction="in"/>
-+      <arg type="h" name="stdin" direction="out"/>
-+      <arg type="h" name="stdout" direction="out"/>
-+      <arg type="h" name="stderr" direction="out"/>
-+    </method>
-+    <property name="version" type="u" access="read"/>
-+  </interface>
-+</node>
-diff --git a/meson.build b/meson.build
-index b25f9ef..8f95fa2 100644
---- a/meson.build
-+++ b/meson.build
-@@ -11,9 +11,11 @@ project(
- 
- prefix = get_option('prefix')
- datadir = prefix / get_option('datadir')
-+libdir = prefix / get_option('libdir')
- libexecdir = prefix / get_option('libexecdir')
- sysconfdir = prefix / get_option('sysconfdir')
- localedir = prefix / get_option('localedir')
-+sysconfdir = prefix / get_option('sysconfdir')
- dbus_service_dir = get_option('dbus-service-dir')
- if dbus_service_dir == ''
-     dbus_service_dir = prefix /  datadir / 'dbus-1' / 'services'
-@@ -78,6 +80,7 @@ config_h = configuration_data()
- config_h.set('_GNU_SOURCE', 1)
- config_h.set_quoted('G_LOG_DOMAIN', 'xdg-desktop-portal')
- config_h.set_quoted('DATADIR', datadir)
-+config_h.set_quoted('LIBDIR', libdir)
- config_h.set_quoted('LIBEXECDIR', libexecdir)
- config_h.set_quoted('LOCALEDIR', localedir)
- config_h.set_quoted('SYSCONFDIR', sysconfdir)
-diff --git a/src/meson.build b/src/meson.build
-index 44d2d51..d01adad 100644
---- a/src/meson.build
-+++ b/src/meson.build
-@@ -84,6 +84,7 @@ xdg_desktop_portal_sources = files(
-   'settings.c',
-   'trash.c',
-   'wallpaper.c',
-+  'web-extensions.c',
-   'xdg-desktop-portal.c',
-   'xdp-utils.c',
- )
-diff --git a/src/request.c b/src/request.c
-index 4216696..73824c8 100644
---- a/src/request.c
-+++ b/src/request.c
-@@ -371,6 +371,18 @@ get_token (GDBusMethodInvocation *invocation)
-                      interface, method, G_STRLOC);
-         }
-     }
-+  else if (strcmp (interface, "org.freedesktop.portal.WebExtensions") == 0)
-+    {
-+      if (strcmp (method, "Start") == 0)
-+        {
-+          options = g_variant_get_child_value (parameters, 3);
-+        }
-+      else
-+        {
-+          g_warning ("Support for %s::%s missing in %s",
-+                     interface, method, G_STRLOC);
-+        }
-+    }
-   else
-     {
-       g_print ("Support for %s missing in " G_STRLOC, interface);
-diff --git a/src/web-extensions.c b/src/web-extensions.c
-new file mode 100644
-index 0000000..181ed21
---- /dev/null
-+++ b/src/web-extensions.c
-@@ -0,0 +1,719 @@
-+/*
-+ * Copyright © 2022 Canonical Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#include "config.h"
-+
-+#include <stdint.h>
-+#include <sys/types.h>
-+#include <sys/wait.h>
-+#include <glib/gi18n.h>
-+#include <gio/gunixfdlist.h>
-+#include <json-glib/json-glib.h>
-+
-+#include "session.h"
-+#include "web-extensions.h"
-+#include "request.h"
-+#include "permissions.h"
-+#include "xdp-dbus.h"
-+#include "xdp-impl-dbus.h"
-+#include "xdp-utils.h"
-+
-+#define PERMISSION_TABLE "webextensions"
-+
-+typedef struct _WebExtensions WebExtensions;
-+typedef struct _WebExtensionsClass WebExtensionsClass;
-+
-+struct _WebExtensions
-+{
-+  XdpDbusWebExtensionsSkeleton parent_instance;
-+};
-+
-+struct _WebExtensionsClass
-+{
-+  XdpDbusWebExtensionsSkeletonClass parent_class;
-+};
-+
-+static XdpDbusImplAccess *access_impl;
-+static WebExtensions *web_extensions;
-+
-+GType web_extensions_get_type (void);
-+static void web_extensions_iface_init (XdpDbusWebExtensionsIface *iface);
-+
-+G_DEFINE_TYPE_WITH_CODE (WebExtensions, web_extensions, XDP_DBUS_TYPE_WEB_EXTENSIONS_SKELETON,
-+                         G_IMPLEMENT_INTERFACE (XDP_DBUS_TYPE_WEB_EXTENSIONS,
-+                                                web_extensions_iface_init));
-+
-+typedef enum _WebExtensionsSessionState
-+{
-+  WEB_EXTENSIONS_SESSION_STATE_INIT,
-+  WEB_EXTENSIONS_SESSION_STATE_STARTING,
-+  WEB_EXTENSIONS_SESSION_STATE_STARTED,
-+  WEB_EXTENSIONS_SESSION_STATE_CLOSED,
-+} WebExtensionsSessionState;
-+
-+typedef struct _WebExtensionsSession
-+{
-+  Session parent;
-+
-+  WebExtensionsSessionState state;
-+
-+  GPid child_pid;
-+  guint child_watch_id;
-+
-+  int standard_input;
-+  int standard_output;
-+  int standard_error;
-+} WebExtensionsSession;
-+
-+typedef struct _WebExtensionsSessionClass
-+{
-+  SessionClass parent_class;
-+} WebExtensionsSessionClass;
-+
-+GType web_extensions_session_get_type (void);
-+
-+G_DEFINE_TYPE (WebExtensionsSession, web_extensions_session, session_get_type ());
-+
-+static void
-+web_extensions_session_init (WebExtensionsSession *session)
-+{
-+  session->child_pid = -1;
-+  session->child_watch_id = 0;
-+
-+  session->standard_input = -1;
-+  session->standard_output = -1;
-+  session->standard_error = -1;
-+}
-+
-+static void
-+web_extensions_session_close (Session *session)
-+{
-+  WebExtensionsSession *web_extensions_session = (WebExtensionsSession *)session;
-+
-+  if (web_extensions_session->state == WEB_EXTENSIONS_SESSION_STATE_CLOSED) return;
-+
-+  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_CLOSED;
-+  if (web_extensions_session->child_watch_id != 0)
-+    {
-+      g_source_remove (web_extensions_session->child_watch_id);
-+      web_extensions_session->child_watch_id = 0;
-+    }
-+
-+  if (web_extensions_session->child_pid > 0)
-+    {
-+      kill (web_extensions_session->child_pid, SIGTERM);
-+      waitpid (web_extensions_session->child_pid, NULL, 0);
-+      g_spawn_close_pid (web_extensions_session->child_pid);
-+      web_extensions_session->child_pid = -1;
-+    }
-+
-+  if (web_extensions_session->standard_input >= 0)
-+    {
-+      close (web_extensions_session->standard_input);
-+      web_extensions_session->standard_input = -1;
-+    }
-+  if (web_extensions_session->standard_output >= 0)
-+    {
-+      close (web_extensions_session->standard_output);
-+      web_extensions_session->standard_output = -1;
-+    }
-+  if (web_extensions_session->standard_error >= 0)
-+    {
-+      close (web_extensions_session->standard_error);
-+      web_extensions_session->standard_error = -1;
-+    }
-+}
-+
-+static void
-+web_extensions_session_finalize (GObject *object)
-+{
-+  Session *session = (Session *)object;
-+
-+  web_extensions_session_close (session);
-+  G_OBJECT_CLASS (web_extensions_session_parent_class)->finalize (object);
-+}
-+
-+static void
-+web_extensions_session_class_init (WebExtensionsSessionClass *klass)
-+{
-+  GObjectClass *object_class;
-+  SessionClass *session_class;
-+
-+  object_class = G_OBJECT_CLASS (klass);
-+  object_class->finalize = web_extensions_session_finalize;
-+
-+  session_class = (SessionClass *)klass;
-+  session_class->close = web_extensions_session_close;
-+}
-+
-+static WebExtensionsSession *
-+web_extensions_session_new (GVariant *options,
-+                            Call *call,
-+                            GDBusConnection *connection,
-+                            GError **error)
-+{
-+  Session *session;
-+  const char *session_token;
-+
-+  session_token = lookup_session_token (options);
-+  session = g_initable_new (web_extensions_session_get_type (), NULL, error,
-+                            "sender", call->sender,
-+                            "app-id", xdp_app_info_get_id (call->app_info),
-+                            "token", session_token,
-+                            "connection", connection,
-+                            NULL);
-+
-+  if (session)
-+    g_debug ("webextensions session owned by '%s' created", session->sender);
-+
-+  return (WebExtensionsSession *)session;
-+}
-+
-+static gboolean
-+handle_create_session (XdpDbusWebExtensions *object,
-+                       GDBusMethodInvocation *invocation,
-+                       GVariant *arg_options)
-+{
-+  Call *call = call_from_invocation (invocation);
-+  GDBusConnection *connection = g_dbus_method_invocation_get_connection (invocation);
-+  g_autoptr(GError) error = NULL;
-+  Session *session;
-+
-+  session = (Session *)web_extensions_session_new (arg_options, call, connection, &error);
-+  if (!session)
-+    {
-+      g_dbus_method_invocation_return_gerror (invocation, error);
-+      return TRUE;
-+    }
-+  if (!session_export (session, &error))
-+    {
-+      g_dbus_method_invocation_return_gerror (invocation, error);
-+      session_close (session, FALSE);
-+      return TRUE;
-+    }
-+  session_register (session);
-+
-+  xdp_dbus_web_extensions_complete_create_session (object, invocation, session->id);
-+
-+  return TRUE;
-+}
-+
-+static void
-+on_server_exited (GPid pid,
-+                  gint status,
-+                  gpointer user_data)
-+{
-+  Session *session = user_data;
-+  WebExtensionsSession *web_extensions_session = (WebExtensionsSession *)session;
-+
-+  SESSION_AUTOLOCK (session);
-+  web_extensions_session->child_pid = -1;
-+  web_extensions_session->child_watch_id = 0;
-+  session_close (session, TRUE);
-+}
-+
-+static gboolean
-+array_contains (JsonArray *array,
-+                const char *value)
-+{
-+  guint length, i;
-+
-+  if (array == NULL)
-+    return FALSE;
-+
-+  length = json_array_get_length (array);
-+  for (i = 0; i < length; i++)
-+    {
-+      const char *element = json_array_get_string_element (array, i);
-+      if (g_strcmp0 (element, value) == 0)
-+        return TRUE;
-+    }
-+  return FALSE;
-+}
-+
-+static gboolean
-+is_valid_name (const char *name)
-+{
-+  /* This regexp comes from the Mozilla documentation on valid native
-+     messaging server names:
-+
-+     https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#native_messaging_manifests
-+
-+     That is, one or more dot-separated groups composed of
-+     alphanumeric characters and underscores.
-+  */
-+  return g_regex_match_simple ("^\\w+(\\.\\w+)*$", name, 0, 0);
-+}
-+
-+static GStrv
-+get_manifest_search_path (void)
-+{
-+  const char *hosts_path_str;
-+  g_autoptr(GPtrArray) search_path = NULL;
-+
-+  hosts_path_str = g_getenv ("XDG_DESKTOP_PORTAL_WEB_EXTENSIONS_PATH");
-+  if (hosts_path_str != NULL)
-+    return g_strsplit (hosts_path_str, ":", -1);
-+
-+  /* By default, use the native messaging search paths of Firefox,
-+   * Chrome, and Chromium, as documented here:
-+   *
-+   * https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#manifest_location
-+   * https://developer.chrome.com/docs/apps/nativeMessaging/#native-messaging-host-location
-+   */
-+
-+  search_path = g_ptr_array_new_with_free_func (g_free);
-+  /* Add per-user directories */
-+  g_ptr_array_add (search_path, g_build_filename (g_get_home_dir (), ".mozilla", "native-messaging-hosts", NULL));
-+  g_ptr_array_add (search_path, g_build_filename (g_get_user_config_dir (), "google-chrome", "NativeMessagingHosts", NULL));
-+  g_ptr_array_add (search_path, g_build_filename (g_get_user_config_dir (), "chromium", "NativeMessagingHosts", NULL));
-+
-+  /* Add system wide directories */
-+  g_ptr_array_add (search_path, g_strdup ("/usr/lib/mozilla/native-messaging-hosts"));
-+  g_ptr_array_add (search_path, g_strdup ("/usr/lib64/mozilla/native-messaging-hosts"));
-+  g_ptr_array_add (search_path, g_strdup ("/etc/opt/chrome/native-messaging-hosts"));
-+  g_ptr_array_add (search_path, g_strdup ("/etc/chromium/native-messaging-hosts"));
-+
-+  /* And the same for xdg-desktop-portal's configured prefix */
-+  g_ptr_array_add (search_path, g_strdup (LIBDIR "mozilla/native-messaging-hosts"));
-+  g_ptr_array_add (search_path, g_strdup (SYSCONFDIR "opt/chrome/native-messaging-hosts"));
-+  g_ptr_array_add (search_path, g_strdup (SYSCONFDIR "chromium/native-messaging-hosts"));
-+
-+  g_ptr_array_add (search_path, NULL);
-+  return (GStrv)g_ptr_array_free (g_steal_pointer (&search_path), FALSE);
-+}
-+
-+static char *
-+find_server (const char *server_name,
-+             const char *extension_or_origin,
-+             char **out_server_description,
-+             char **out_json_manifest,
-+             GError **error)
-+{
-+  g_auto(GStrv) search_path = NULL;
-+  g_autoptr(JsonParser) parser = NULL;
-+  g_autofree char *metadata_basename = NULL;
-+  int i;
-+
-+  /* Check that the we have a valid native messaging host name */
-+  if (!is_valid_name (server_name))
-+    {
-+      g_set_error (error,
-+                   XDG_DESKTOP_PORTAL_ERROR,
-+                   XDG_DESKTOP_PORTAL_ERROR_INVALID_ARGUMENT,
-+                   "Invalid native messaging server name");
-+      return NULL;
-+    }
-+
-+  search_path = get_manifest_search_path ();
-+  parser = json_parser_new ();
-+  metadata_basename = g_strconcat (server_name, ".json", NULL);
-+
-+  for (i = 0; search_path[i] != NULL; i++)
-+    {
-+      g_autofree char *metadata_filename = NULL;
-+      g_autoptr(GError) load_error = NULL;
-+      JsonObject *metadata_root;
-+
-+      metadata_filename = g_build_filename (search_path[i], metadata_basename, NULL);
-+      if (!json_parser_load_from_file (parser, metadata_filename, &load_error))
-+        {
-+          /* If the file doesn't exist, continue searching. Error out
-+             on anything else. */
-+          if (g_error_matches (load_error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
-+            continue;
-+          g_propagate_error (error, g_steal_pointer (&load_error));
-+          return NULL;
-+        }
-+
-+      metadata_root = json_node_get_object (json_parser_get_root (parser));
-+
-+      /* Skip if metadata contains an unexpected name */
-+      if (g_strcmp0 (json_object_get_string_member (metadata_root, "name"), server_name) != 0)
-+        continue;
-+
-+      /* Skip if this is not a "stdio" type native messaging server */
-+      if (g_strcmp0 (json_object_get_string_member (metadata_root, "type"), "stdio") != 0)
-+        continue;
-+
-+      /* Skip if this server isn't available to the extension. Note
-+       * that this ID is provided by the sandboxed browser, so this
-+       * check is just to help implement its security policy. */
-+      if (!array_contains (json_object_get_array_member (metadata_root, "allowed_extensions"), extension_or_origin) &&
-+          !array_contains (json_object_get_array_member (metadata_root, "allowed_origins"), extension_or_origin))
-+        continue;
-+
-+      /* Server matches: return its executable path and description */
-+      if (out_server_description != NULL)
-+          *out_server_description = g_strdup (json_object_get_string_member (metadata_root, "description"));
-+      if (out_json_manifest != NULL)
-+          *out_json_manifest = json_to_string (json_parser_get_root (parser), FALSE);
-+      return g_strdup (json_object_get_string_member (metadata_root, "path"));
-+    }
-+
-+  g_set_error (error,
-+               XDG_DESKTOP_PORTAL_ERROR,
-+               XDG_DESKTOP_PORTAL_ERROR_NOT_FOUND,
-+               "Could not find native messaging server");
-+  return NULL;
-+}
-+
-+static gboolean
-+handle_get_manifest (XdpDbusWebExtensions *object,
-+                     GDBusMethodInvocation *invocation,
-+                     const char *arg_session_handle,
-+                     const char *arg_name,
-+                     const char *arg_extension_or_origin)
-+{
-+  Call *call = call_from_invocation (invocation);
-+  Session *session;
-+  WebExtensionsSession *web_extensions_session;
-+  g_autofree char *server_path = NULL;
-+  g_autofree char *json_manifest = NULL;
-+  g_autoptr(GError) error = NULL;
-+
-+  session = acquire_session_from_call (arg_session_handle, call);
-+  if (!session)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_ACCESS_DENIED,
-+                                             "Invalid session");
-+      return TRUE;
-+    }
-+
-+  SESSION_AUTOLOCK_UNREF (session);
-+  web_extensions_session = (WebExtensionsSession *)session;
-+
-+  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_INIT)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_FAILED,
-+                                             "Session already started");
-+      return TRUE;
-+    }
-+
-+  server_path = find_server (arg_name, arg_extension_or_origin,
-+                             NULL, &json_manifest, &error);
-+  if (!server_path)
-+    {
-+      g_dbus_method_invocation_return_gerror (invocation, error);
-+      return TRUE;
-+    }
-+
-+  xdp_dbus_web_extensions_complete_get_manifest (object, invocation, json_manifest);
-+  return TRUE;
-+}
-+
-+static void
-+handle_start_in_thread (GTask *task,
-+                        gpointer source_object,
-+                        gpointer task_data,
-+                        GCancellable *cancellable)
-+{
-+  Request *request = (Request *)task_data;
-+  Session *session;
-+  WebExtensionsSession *web_extensions_session;
-+  const char *arg_name;
-+  const char *arg_extension_or_origin;
-+  const char *app_id;
-+  g_autofree char *server_path = NULL;
-+  g_autofree char *server_description = NULL;
-+  guint response = XDG_DESKTOP_PORTAL_RESPONSE_OTHER;
-+  gboolean should_close_session;
-+  Permission permission;
-+  gboolean allowed;
-+  char *argv[] = {NULL, NULL};
-+  g_autoptr(GError) error = NULL;
-+
-+  REQUEST_AUTOLOCK (request);
-+  session = g_object_get_data (G_OBJECT (request), "session");
-+  SESSION_AUTOLOCK_UNREF (g_object_ref (session));
-+  g_object_set_data (G_OBJECT (request), "session", NULL);
-+  web_extensions_session = (WebExtensionsSession *)session;
-+
-+  if (!request->exported || web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_STARTING)
-+    goto out;
-+
-+  arg_name = g_object_get_data (G_OBJECT (request), "name");
-+  arg_extension_or_origin = g_object_get_data (G_OBJECT (request), "extension-or-origin");
-+
-+  server_path = find_server (arg_name, arg_extension_or_origin, &server_description, NULL, &error);
-+  if (server_path == NULL)
-+    {
-+      g_warning ("Could not find WebExtensions backend: %s", error->message);
-+      fflush(stderr);
-+      fflush(stdout);
-+      goto out;
-+    }
-+
-+  app_id = xdp_app_info_get_id (request->app_info);
-+  permission = get_permission_sync (app_id, PERMISSION_TABLE, arg_name);
-+  if (permission == PERMISSION_ASK || permission == PERMISSION_UNSET)
-+    {
-+      guint access_response = 2;
-+      g_autoptr(GVariant) access_results = NULL;
-+      GVariantBuilder opt_builder;
-+      g_autoptr(GAppInfo) info = NULL;
-+      const char *display_name;
-+      g_autofree gchar *app_info_id = NULL;
-+      g_autofree gchar *title = NULL;
-+      g_autofree gchar *subtitle = NULL;
-+      g_autofree gchar *body = NULL;
-+
-+      info = xdp_app_info_load_app_info (request->app_info);
-+      if (info)
-+        {
-+          g_auto(GStrv) app_id_components = g_strsplit (g_app_info_get_id (info), ".desktop", 2);
-+          app_info_id = g_strdup (app_id_components[0]);
-+        }
-+      display_name = info ? g_app_info_get_display_name (info) : app_id;
-+      title = g_strdup_printf (_("Allow %s to start WebExtension backend?"), display_name);
-+      subtitle = g_strdup_printf (_("%s is requesting to launch \"%s\" (%s)."), display_name, server_description, arg_name);
-+      body = g_strdup (_("This permission can be changed at any time from the privacy settings."));
-+
-+      g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
-+      g_variant_builder_add (&opt_builder, "{sv}", "deny_label", g_variant_new_string (_("Don't allow")));
-+      g_variant_builder_add (&opt_builder, "{sv}", "grant_label", g_variant_new_string (_("Allow")));
-+      if (!xdp_dbus_impl_access_call_access_dialog_sync (access_impl,
-+                                                         request->id,
-+                                                         app_info_id ? app_info_id : app_id,
-+                                                         "",
-+                                                         title,
-+                                                         subtitle,
-+                                                         body,
-+                                                         g_variant_builder_end (&opt_builder),
-+                                                         &access_response,
-+                                                         &access_results,
-+                                                         NULL,
-+                                                         &error))
-+        {
-+          g_warning ("AccessDialog call failed: %s", error->message);
-+          g_clear_error (&error);
-+        }
-+      allowed = access_response == 0;
-+
-+      if (permission == PERMISSION_UNSET)
-+        set_permission_sync (app_id, PERMISSION_TABLE, arg_name, allowed ? PERMISSION_YES : PERMISSION_NO);
-+    }
-+  else
-+    {
-+      allowed = permission == PERMISSION_YES ? TRUE : FALSE;
-+    }
-+
-+  if (!allowed)
-+    {
-+      response = XDG_DESKTOP_PORTAL_RESPONSE_CANCELLED;
-+      goto out;
-+    }
-+
-+  argv[0] = server_path;
-+  if (!g_spawn_async_with_pipes (NULL, /* working_directory */
-+                                 argv,
-+                                 NULL, /* envp */
-+                                 G_SPAWN_DO_NOT_REAP_CHILD,
-+                                 NULL, /* child_setup */
-+                                 NULL, /* user_data */
-+                                 &web_extensions_session->child_pid,
-+                                 &web_extensions_session->standard_input,
-+                                 &web_extensions_session->standard_output,
-+                                 &web_extensions_session->standard_error,
-+                                 &error))
-+    {
-+      web_extensions_session->child_pid = -1;
-+      goto out;
-+    }
-+
-+  web_extensions_session->child_watch_id = g_child_watch_add_full (G_PRIORITY_DEFAULT,
-+                                                                   web_extensions_session->child_pid,
-+                                                                   on_server_exited,
-+                                                                   g_object_ref (web_extensions_session),
-+                                                                   g_object_unref);
-+  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_STARTED;
-+
-+  response = XDG_DESKTOP_PORTAL_RESPONSE_SUCCESS;
-+
-+out:
-+  should_close_session = !request->exported || response != XDG_DESKTOP_PORTAL_RESPONSE_SUCCESS;
-+
-+  if (request->exported)
-+    {
-+      GVariantBuilder results;
-+
-+      g_variant_builder_init (&results, G_VARIANT_TYPE_VARDICT);
-+      xdp_dbus_request_emit_response (XDP_DBUS_REQUEST (request), response, g_variant_builder_end (&results));
-+      request_unexport (request);
-+    }
-+
-+  if (should_close_session)
-+    session_close (session, TRUE);
-+}
-+
-+static gboolean
-+handle_start (XdpDbusWebExtensions *object,
-+              GDBusMethodInvocation *invocation,
-+              const char *arg_session_handle,
-+              const char *arg_name,
-+              const char *arg_extension_or_origin,
-+              GVariant *arg_options)
-+{
-+  Request *request = request_from_invocation (invocation);
-+  Session *session;
-+  WebExtensionsSession *web_extensions_session;
-+  g_autoptr(GTask) task = NULL;
-+
-+  REQUEST_AUTOLOCK (request);
-+
-+  session = acquire_session (arg_session_handle, request);
-+  if (!session)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_ACCESS_DENIED,
-+                                             "Invalid session");
-+      return TRUE;
-+    }
-+
-+  SESSION_AUTOLOCK_UNREF (session);
-+  web_extensions_session = (WebExtensionsSession *)session;
-+
-+  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_INIT)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_FAILED,
-+                                             "Session already started");
-+      return TRUE;
-+    }
-+
-+  web_extensions_session->state = WEB_EXTENSIONS_SESSION_STATE_STARTING;
-+  g_object_set_data_full (G_OBJECT (request), "session", g_object_ref (session), g_object_unref);
-+  g_object_set_data_full (G_OBJECT (request), "name", g_strdup (arg_name), g_free);
-+  g_object_set_data_full (G_OBJECT (request), "extension-or-origin", g_strdup (arg_extension_or_origin), g_free);
-+
-+  request_export (request, g_dbus_method_invocation_get_connection (invocation));
-+  xdp_dbus_web_extensions_complete_start (object, invocation, request->id);
-+
-+  task = g_task_new (object, NULL, NULL, NULL);
-+  g_task_set_task_data (task, g_object_ref (request), g_object_unref);
-+  g_task_run_in_thread (task, handle_start_in_thread);
-+
-+  return TRUE;
-+}
-+
-+
-+static gboolean
-+handle_get_pipes (XdpDbusWebExtensions *object,
-+                  GDBusMethodInvocation *invocation,
-+                  GUnixFDList *fd_list,
-+                  const char *arg_session_handle,
-+                  GVariant *arg_options)
-+{
-+  Call *call = call_from_invocation (invocation);
-+  Session *session;
-+  WebExtensionsSession *web_extensions_session;
-+  int fds[3];
-+  g_autoptr(GUnixFDList) out_fd_list = NULL;
-+
-+  session = acquire_session_from_call (arg_session_handle, call);
-+  if (!session)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_ACCESS_DENIED,
-+                                             "Invalid session");
-+      return TRUE;
-+    }
-+
-+  SESSION_AUTOLOCK_UNREF (session);
-+  web_extensions_session = (WebExtensionsSession *)session;
-+
-+  if (web_extensions_session->state != WEB_EXTENSIONS_SESSION_STATE_STARTED)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_FAILED,
-+                                             "Session not started");
-+      return TRUE;
-+    }
-+
-+  if (web_extensions_session->standard_input < 0 ||
-+      web_extensions_session->standard_output < 0 ||
-+      web_extensions_session->standard_error < 0)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             G_DBUS_ERROR,
-+                                             G_DBUS_ERROR_FAILED,
-+                                             "GetPipes already called");
-+      return TRUE;
-+    }
-+
-+  fds[0] = web_extensions_session->standard_input;
-+  fds[1] = web_extensions_session->standard_output;
-+  fds[2] = web_extensions_session->standard_error;
-+  out_fd_list = g_unix_fd_list_new_from_array (fds, G_N_ELEMENTS (fds));
-+  /* out_fd_list now owns the file descriptors */
-+  web_extensions_session->standard_input = -1;
-+  web_extensions_session->standard_output = -1;
-+  web_extensions_session->standard_error = -1;
-+
-+  xdp_dbus_web_extensions_complete_get_pipes (object, invocation, out_fd_list,
-+                                              g_variant_new_handle (0),
-+                                              g_variant_new_handle (1),
-+                                              g_variant_new_handle (2));
-+  return TRUE;
-+}
-+
-+static void
-+web_extensions_iface_init (XdpDbusWebExtensionsIface *iface)
-+{
-+  iface->handle_create_session = handle_create_session;
-+  iface->handle_get_manifest = handle_get_manifest;
-+  iface->handle_start = handle_start;
-+  iface->handle_get_pipes = handle_get_pipes;
-+}
-+
-+static void
-+web_extensions_init (WebExtensions *web_extensions)
-+{
-+  xdp_dbus_web_extensions_set_version (XDP_DBUS_WEB_EXTENSIONS (web_extensions), 1);
-+}
-+
-+static void
-+web_extensions_class_init (WebExtensionsClass *klass)
-+{
-+}
-+
-+GDBusInterfaceSkeleton *
-+web_extensions_create (GDBusConnection *connection,
-+                       const char *dbus_name_access)
-+{
-+  g_autoptr(GError) error = NULL;
-+
-+  web_extensions = g_object_new (web_extensions_get_type (), NULL);
-+
-+  access_impl = xdp_dbus_impl_access_proxy_new_sync (connection,
-+                                                     G_DBUS_PROXY_FLAGS_NONE,
-+                                                     dbus_name_access,
-+                                                     DESKTOP_PORTAL_OBJECT_PATH,
-+                                                     NULL,
-+                                                     &error);
-+
-+  return G_DBUS_INTERFACE_SKELETON (web_extensions);
-+}
-diff --git a/src/web-extensions.h b/src/web-extensions.h
-new file mode 100644
-index 0000000..72b947a
---- /dev/null
-+++ b/src/web-extensions.h
-@@ -0,0 +1,24 @@
-+/*
-+ * Copyright © 2022 Canonical Ltd
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2 of the License, or (at your option) any later version.
-+ *
-+ * This library is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
-+ *
-+ */
-+
-+#pragma once
-+
-+#include <gio/gio.h>
-+
-+GDBusInterfaceSkeleton *web_extensions_create (GDBusConnection *connection,
-+                                               const char *access_dbus_name);
-diff --git a/src/xdg-desktop-portal.c b/src/xdg-desktop-portal.c
-index 1577525..4ac2238 100644
---- a/src/xdg-desktop-portal.c
-+++ b/src/xdg-desktop-portal.c
-@@ -63,6 +63,7 @@
- #include "settings.h"
- #include "trash.h"
- #include "wallpaper.h"
-+#include "web-extensions.h"
- 
- static GMainLoop *loop = NULL;
- 
-@@ -162,6 +163,13 @@ method_needs_request (GDBusMethodInvocation *invocation)
-       else
-         return TRUE;
-     }
-+  else if (strcmp (interface, "org.freedesktop.portal.WebExtensions") == 0)
-+    {
-+      if (strcmp (method, "Start") == 0)
-+        return TRUE;
-+      else
-+        return FALSE;
-+    }
-   else
-     {
-       return TRUE;
-@@ -307,6 +315,9 @@ on_bus_acquired (GDBusConnection *connection,
-                                     device_create (connection,
-                                                    access_impl->dbus_name,
-                                                    lockdown));
-+      export_portal_implementation (connection,
-+                                    web_extensions_create (connection,
-+                                                           access_impl->dbus_name));
- #ifdef HAVE_GEOCLUE
-       export_portal_implementation (connection,
-                                     location_create (connection,
-diff --git a/tests/meson.build b/tests/meson.build
-index b91800f..5693db8 100644
---- a/tests/meson.build
-+++ b/tests/meson.build
-@@ -15,6 +15,7 @@ subdir('dbs')
- subdir('portals')
- subdir('services')
- subdir('share')
-+subdir('native-messaging-hosts')
- 
- test_db = executable(
-   'testdb',
-@@ -114,6 +115,7 @@ if have_libportal
-     'screenshot.c',
-     'trash.c',
-     'wallpaper.c',
-+    'web-extensions.c',
-     'glib-backports.c',
-   )
- 
-@@ -177,6 +179,7 @@ portal_tests = [
-   'screenshot',
-   'trash',
-   'wallpaper',
-+  'webextensions',
- ]
- 
- test_env = env_tests
-diff --git a/tests/native-messaging-hosts/meson.build b/tests/native-messaging-hosts/meson.build
-new file mode 100644
-index 0000000..726f54f
---- /dev/null
-+++ b/tests/native-messaging-hosts/meson.build
-@@ -0,0 +1,6 @@
-+test_portal = configure_file(input: 'org.example.testing.json',
-+    output: '@PLAINNAME@',
-+    copy: true,
-+    install: enable_installed_tests,
-+    install_dir: installed_tests_dir / 'native-messaging-hosts',
-+)
-diff --git a/tests/native-messaging-hosts/org.example.testing.json b/tests/native-messaging-hosts/org.example.testing.json
-new file mode 100644
-index 0000000..93b2f11
---- /dev/null
-+++ b/tests/native-messaging-hosts/org.example.testing.json
-@@ -0,0 +1,9 @@
-+{
-+  "name": "org.example.testing",
-+  "description": "Test native messaging host",
-+  "path": "/bin/cat",
-+  "type": "stdio",
-+  "allowed_extensions": [
-+    "some-extension at example.org"
-+  ]
-+}
-diff --git a/tests/test-portals.c b/tests/test-portals.c
-index bae93a5..d9b9435 100644
---- a/tests/test-portals.c
-+++ b/tests/test-portals.c
-@@ -23,6 +23,7 @@
- #include "screenshot.h"
- #include "trash.h"
- #include "wallpaper.h"
-+#include "web-extensions.h"
- #endif
- 
- #include "utils.h"
-@@ -136,6 +137,7 @@ global_setup (void)
-   g_autofree gchar *backends_executable = NULL;
-   g_autofree gchar *services = NULL;
-   g_autofree gchar *portal_dir = NULL;
-+  g_autofree gchar *web_extensions_dir = NULL;
-   g_autofree gchar *argv0 = NULL;
-   g_autoptr(GSubprocessLauncher) launcher = NULL;
-   g_autoptr(GSubprocess) subprocess = NULL;
-@@ -266,12 +268,14 @@ global_setup (void)
-                                           NULL);
- 
-   portal_dir = g_test_build_filename (G_TEST_BUILT, "portals", "test", NULL);
-+  web_extensions_dir = g_test_build_filename (G_TEST_DIST, "native-messaging-hosts", NULL);
- 
-   g_clear_object (&launcher);
-   launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_NONE);
-   g_subprocess_launcher_setenv (launcher, "G_DEBUG", "fatal-criticals", TRUE);
-   g_subprocess_launcher_setenv (launcher, "DBUS_SESSION_BUS_ADDRESS", g_test_dbus_get_bus_address (dbus), TRUE);
-   g_subprocess_launcher_setenv (launcher, "XDG_DESKTOP_PORTAL_DIR", portal_dir, TRUE);
-+  g_subprocess_launcher_setenv (launcher, "XDG_DESKTOP_PORTAL_WEB_EXTENSIONS_PATH", web_extensions_dir, TRUE);
-   g_subprocess_launcher_setenv (launcher, "XDG_DATA_HOME", outdir, TRUE);
-   g_subprocess_launcher_setenv (launcher, "PATH", g_getenv ("PATH"), TRUE);
-   g_subprocess_launcher_take_stdout_fd (launcher, xdup (STDERR_FILENO));
-@@ -584,6 +588,9 @@ main (int argc, char **argv)
-   g_test_add_func ("/portal/notification/bad-arg", test_notification_bad_arg);
-   g_test_add_func ("/portal/notification/bad-priority", test_notification_bad_priority);
-   g_test_add_func ("/portal/notification/bad-button", test_notification_bad_button);
-+
-+  g_test_add_func ("/portal/webextensions/basic", test_web_extensions_basic);
-+  g_test_add_func ("/portal/webextensions/bad-name", test_web_extensions_bad_name);
- #endif
- 
-   global_setup ();
-diff --git a/tests/web-extensions.c b/tests/web-extensions.c
-new file mode 100644
-index 0000000..761f6d5
---- /dev/null
-+++ b/tests/web-extensions.c
-@@ -0,0 +1,610 @@
-+#include <config.h>
-+
-+#include "web-extensions.h"
-+#include "xdp-utils.h"
-+
-+#include <gio/gio.h>
-+#include <gio/gunixfdlist.h>
-+#include "xdp-impl-dbus.h"
-+
-+// TODO: convert these simple client wrappers to proper libportal APIs
-+
-+static void
-+create_session_returned (GObject *object,
-+                         GAsyncResult *result,
-+                         gpointer data)
-+{
-+  g_autoptr(GTask) task = data;
-+  g_autoptr(GVariant) ret = NULL;
-+  GError *error = NULL;
-+  g_autofree char *session_handle = NULL;
-+
-+  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
-+  if (!ret)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+  g_variant_get (ret, "(o)", &session_handle);
-+  g_task_return_pointer (task, g_steal_pointer (&session_handle), g_free);
-+}
-+
-+static void
-+create_session (GCancellable *cancellable,
-+                GAsyncReadyCallback callback,
-+                gpointer data)
-+{
-+  g_autoptr(GTask) task = NULL;
-+  g_autoptr(GDBusConnection) session_bus = NULL;
-+  GError *error = NULL;
-+  g_autofree char *session_token = NULL;
-+  GVariantBuilder options;
-+
-+  task = g_task_new (NULL, cancellable, callback, data);
-+
-+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-+  if (session_bus == NULL)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+
-+  session_token = g_strdup_printf ("portal%d", g_random_int_range (0, G_MAXINT));
-+  g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
-+  g_variant_builder_add (&options, "{sv}", "session_handle_token", g_variant_new_string (session_token));
-+  g_dbus_connection_call (session_bus,
-+                          "org.freedesktop.portal.Desktop",
-+                          "/org/freedesktop/portal/desktop",
-+                          "org.freedesktop.portal.WebExtensions",
-+                          "CreateSession",
-+                          g_variant_new ("(a{sv})", &options),
-+                          NULL,
-+                          G_DBUS_CALL_FLAGS_NONE,
-+                          -1,
-+                          cancellable,
-+                          create_session_returned,
-+                          g_steal_pointer (&task));
-+}
-+
-+static char *
-+create_session_finish (GAsyncResult *result, GError **error)
-+{
-+  return g_task_propagate_pointer (G_TASK (result), error);
-+}
-+
-+static void
-+get_manifest_returned (GObject *object,
-+                       GAsyncResult *result,
-+                       gpointer data)
-+{
-+  g_autoptr(GTask) task = data;
-+  g_autoptr(GVariant) ret = NULL;
-+  GError *error = NULL;
-+  g_autofree char *json_manifest = NULL;
-+
-+  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
-+  if (!ret)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+  g_variant_get (ret, "(s)", &json_manifest);
-+  g_task_return_pointer (task, g_steal_pointer (&json_manifest), g_free);
-+}
-+
-+static void
-+get_manifest (const char *session_handle,
-+              const char *name,
-+              const char *extension_or_origin,
-+              GCancellable *cancellable,
-+              GAsyncReadyCallback callback,
-+              gpointer data)
-+{
-+  g_autoptr(GTask) task = NULL;
-+  g_autoptr(GDBusConnection) session_bus = NULL;
-+  GError *error = NULL;
-+
-+  task = g_task_new (NULL, cancellable, callback, data);
-+
-+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-+  if (session_bus == NULL)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+
-+  g_dbus_connection_call (session_bus,
-+                          "org.freedesktop.portal.Desktop",
-+                          "/org/freedesktop/portal/desktop",
-+                          "org.freedesktop.portal.WebExtensions",
-+                          "GetManifest",
-+                          g_variant_new ("(oss)", session_handle, name, extension_or_origin),
-+                          NULL,
-+                          G_DBUS_CALL_FLAGS_NONE,
-+                          -1,
-+                          cancellable,
-+                          get_manifest_returned,
-+                          g_steal_pointer (&task));
-+}
-+
-+static char *
-+get_manifest_finish (GAsyncResult *result, GError **error)
-+{
-+  return g_task_propagate_pointer (G_TASK (result), error);
-+}
-+
-+static void
-+start_returned (GObject *object,
-+                GAsyncResult *result,
-+                gpointer data)
-+{
-+  g_autoptr(GTask) task = data;
-+  g_autoptr(GVariant) ret = NULL;
-+  GError *error = NULL;
-+
-+  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
-+  if (!ret)
-+    {
-+      guint signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "response-signal-id"));
-+      g_dbus_connection_signal_unsubscribe (G_DBUS_CONNECTION (object), signal_id);
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+}
-+
-+static void
-+start_completed (GDBusConnection *session_bus,
-+                 const char *sender_name,
-+                 const char *object_path,
-+                 const char *interface_name,
-+                 const char *signal_name,
-+                 GVariant *parameters,
-+                 gpointer data)
-+{
-+  g_autoptr(GTask) task = g_object_ref (data);
-+  guint signal_id;
-+  guint32 response;
-+  g_autoptr(GVariant) ret = NULL;
-+
-+  signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "response-signal-id"));
-+  g_dbus_connection_signal_unsubscribe (session_bus, signal_id);
-+
-+  g_variant_get (parameters, "(u at a{sv})", &response, &ret);
-+  switch (response)
-+    {
-+    case 0:
-+      g_task_return_boolean (task, TRUE);
-+      break;
-+    case 1:
-+      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Start cancelled");
-+      break;
-+    case 2:
-+    default:
-+      g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Start failed");
-+      break;
-+    }
-+}
-+
-+static void
-+start (const char *session_handle,
-+       const char *name,
-+       const char *extension_or_origin,
-+       GCancellable *cancellable,
-+       GAsyncReadyCallback callback,
-+       gpointer data)
-+{
-+  g_autoptr(GTask) task = NULL;
-+  g_autoptr(GDBusConnection) session_bus = NULL;
-+  GError *error = NULL;
-+  g_autofree char *token = NULL;
-+  g_autofree char *sender = NULL;
-+  g_autofree char *request_path = NULL;
-+  int i;
-+  guint signal_id;
-+  GVariantBuilder options;
-+
-+  task = g_task_new (NULL, cancellable, callback, data);
-+
-+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-+  if (session_bus == NULL)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+
-+  token = g_strdup_printf ("portal%d", g_random_int_range (0, G_MAXINT));
-+  sender = g_strdup (g_dbus_connection_get_unique_name (session_bus) + 1);
-+  for (i = 0; sender[i]; i++)
-+    if (sender[i] == '.')
-+      sender[i] = '_';
-+  request_path = g_strconcat ("/org/freedesktop/portal/desktop/request/", sender, "/", token, NULL);
-+  signal_id = g_dbus_connection_signal_subscribe (session_bus,
-+                                                  "org.freedesktop.portal.Desktop",
-+                                                  "org.freedesktop.portal.Request",
-+                                                  "Response",
-+                                                  request_path,
-+                                                  NULL,
-+                                                  G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
-+                                                  start_completed,
-+                                                  g_object_ref (task),
-+                                                  g_object_unref);
-+  g_object_set_data (G_OBJECT (task), "response-signal-id", GUINT_TO_POINTER (signal_id));
-+
-+  g_variant_builder_init (&options, G_VARIANT_TYPE_VARDICT);
-+  g_variant_builder_add (&options, "{sv}", "handle_token", g_variant_new_string (token));
-+  g_dbus_connection_call (session_bus,
-+                          "org.freedesktop.portal.Desktop",
-+                          "/org/freedesktop/portal/desktop",
-+                          "org.freedesktop.portal.WebExtensions",
-+                          "Start",
-+                          g_variant_new ("(ossa{sv})", session_handle, name, extension_or_origin, &options),
-+                          NULL,
-+                          G_DBUS_CALL_FLAGS_NONE,
-+                          -1,
-+                          cancellable,
-+                          start_returned,
-+                          g_steal_pointer (&task));
-+}
-+
-+static gboolean
-+start_finish (GAsyncResult *result, GError **error)
-+{
-+  return g_task_propagate_boolean (G_TASK (result), error);
-+}
-+
-+static void
-+get_pipes_returned (GObject *object,
-+                    GAsyncResult *result,
-+                    gpointer data)
-+{
-+  g_autoptr(GTask) task = data;
-+  g_autoptr(GVariant) ret = NULL;
-+  g_autoptr(GUnixFDList) fd_list = NULL;
-+  GError *error = NULL;
-+
-+  ret = g_dbus_connection_call_with_unix_fd_list_finish (G_DBUS_CONNECTION (object), &fd_list, result, &error);
-+  if (!ret)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+  g_task_return_pointer (task, g_steal_pointer (&fd_list), g_object_unref);
-+}
-+
-+static void
-+get_pipes (const char *session_handle,
-+           GCancellable *cancellable,
-+           GAsyncReadyCallback callback,
-+           gpointer data)
-+{
-+  g_autoptr(GTask) task = NULL;
-+  g_autoptr(GDBusConnection) session_bus = NULL;
-+  GError *error = NULL;
-+
-+  task = g_task_new (NULL, cancellable, callback, data);
-+
-+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-+  if (session_bus == NULL)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+
-+  g_dbus_connection_call_with_unix_fd_list (session_bus,
-+                                            "org.freedesktop.portal.Desktop",
-+                                            "/org/freedesktop/portal/desktop",
-+                                            "org.freedesktop.portal.WebExtensions",
-+                                            "GetPipes",
-+                                            g_variant_new ("(oa{sv})", session_handle, NULL),
-+                                            NULL,
-+                                            G_DBUS_CALL_FLAGS_NONE,
-+                                            -1,
-+                                            NULL,
-+                                            cancellable,
-+                                            get_pipes_returned,
-+                                            g_steal_pointer (&task));
-+}
-+
-+static gboolean
-+get_pipes_finish (int *stdin_fileno, int *stdout_fileno, int *stderr_fileno, GAsyncResult *result, GError **error)
-+{
-+  g_autoptr(GUnixFDList) fd_list = NULL;
-+
-+  fd_list = g_task_propagate_pointer (G_TASK (result), error);
-+  if (fd_list == NULL)
-+    return FALSE;
-+
-+  if (stdin_fileno != NULL)
-+    {
-+      *stdin_fileno = g_unix_fd_list_get (fd_list, 0, error);
-+      if (*stdin_fileno < 0)
-+        return FALSE;
-+    }
-+  if (stdout_fileno != NULL)
-+    {
-+      *stdout_fileno = g_unix_fd_list_get (fd_list, 1, error);
-+      if (*stdout_fileno < 0)
-+        return FALSE;
-+    }
-+  if (stderr_fileno != NULL)
-+    {
-+      *stderr_fileno = g_unix_fd_list_get (fd_list, 2, error);
-+      if (*stderr_fileno < 0)
-+        return FALSE;
-+    }
-+  return TRUE;
-+}
-+
-+static void
-+close_session_returned (GObject *object,
-+                        GAsyncResult *result,
-+                        gpointer data)
-+{
-+  g_autoptr(GTask) task = data;
-+  g_autoptr(GVariant) ret = NULL;
-+  GError *error = NULL;
-+
-+  ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (object), result, &error);
-+  if (!ret)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+  g_task_return_boolean (task, TRUE);
-+}
-+
-+static void
-+close_session (const char *session_handle,
-+               GCancellable *cancellable,
-+               GAsyncReadyCallback callback,
-+               gpointer data)
-+{
-+  g_autoptr(GTask) task = NULL;
-+  g_autoptr(GDBusConnection) session_bus = NULL;
-+  GError *error = NULL;
-+
-+  task = g_task_new (NULL, cancellable, callback, data);
-+
-+  session_bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-+  if (session_bus == NULL)
-+    {
-+      g_task_return_error (task, error);
-+      return;
-+    }
-+
-+  g_dbus_connection_call (session_bus,
-+                          "org.freedesktop.portal.Desktop",
-+                          session_handle,
-+                          "org.freedesktop.portal.Session",
-+                          "Close",
-+                          NULL,
-+                          NULL,
-+                          G_DBUS_CALL_FLAGS_NONE,
-+                          -1,
-+                          cancellable,
-+                          close_session_returned,
-+                          g_steal_pointer (&task));
-+}
-+
-+static gboolean
-+close_session_finish (GAsyncResult *result, GError **error)
-+{
-+  return g_task_propagate_boolean (G_TASK (result), error);
-+}
-+
-+
-+static int got_info = 0;
-+
-+extern XdpDbusImplPermissionStore *permission_store;
-+
-+static void
-+set_web_extensions_permissions (const char *permission)
-+{
-+  const char *permissions[2] = { NULL, NULL };
-+  g_autoptr(GError) error = NULL;
-+
-+  permissions[0] = permission;
-+  xdp_dbus_impl_permission_store_call_set_permission_sync (permission_store,
-+                                                           "webextensions",
-+                                                           TRUE,
-+                                                           "org.example.testing",
-+                                                           "",
-+                                                           permissions,
-+                                                           NULL,
-+                                                           &error);
-+  g_assert_no_error (error);
-+}
-+
-+static gboolean
-+cancel_call (gpointer data)
-+{
-+  GCancellable *cancellable = data;
-+
-+  g_debug ("cancel call");
-+  g_cancellable_cancel (cancellable);
-+
-+  return G_SOURCE_REMOVE;
-+}
-+
-+typedef struct {
-+  GCancellable *cancellable;
-+  char *session_handle;
-+  const char *server_name;
-+} TestData;
-+
-+static void
-+close_session_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  g_autoptr(GError) error = NULL;
-+  gboolean ret;
-+
-+  ret = close_session_finish (result, &error);
-+  if (ret)
-+    {
-+      g_assert_no_error (error);
-+    }
-+  else
-+    {
-+      /* The native messaging host may have closed before we tried to
-+         close it. */
-+      g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
-+    }
-+
-+  got_info++;
-+  g_main_context_wakeup (NULL);
-+}
-+
-+static void
-+get_pipes_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  TestData *test_data = data;
-+  g_autoptr(GError) error = NULL;
-+  gboolean ret;
-+  int stdin_fileno = -1, stdout_fileno = -1, stderr_fileno = -1;
-+
-+  ret = get_pipes_finish (&stdin_fileno, &stdout_fileno, &stderr_fileno, result, &error);
-+  g_assert_no_error (error);
-+  g_assert_true (ret);
-+  g_assert_cmpint (stdin_fileno, >, 0);
-+  g_assert_cmpint (stdout_fileno, >, 0);
-+  g_assert_cmpint (stderr_fileno, >, 0);
-+
-+  close (stdin_fileno);
-+  close (stdout_fileno);
-+  close (stderr_fileno);
-+
-+  close_session (test_data->session_handle,
-+                 test_data->cancellable,
-+                 close_session_cb,
-+                 test_data);
-+}
-+
-+static void
-+start_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  TestData *test_data = data;
-+  g_autoptr(GError) error = NULL;
-+  gboolean ret;
-+
-+  ret = start_finish (result, &error);
-+  g_assert_no_error (error);
-+  g_assert_true (ret);
-+
-+  get_pipes (test_data->session_handle,
-+             test_data->cancellable,
-+             get_pipes_cb,
-+             test_data);
-+}
-+
-+
-+static void
-+get_manifest_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  TestData *test_data = data;
-+  g_autoptr(GError) error = NULL;
-+  g_autofree char *json_manifest = NULL;
-+
-+  json_manifest = get_manifest_finish (result, &error);
-+  g_assert_no_error (error);
-+  g_assert_cmpstr (json_manifest, ==, "{\"name\":\"org.example.testing\",\"description\":\"Test native messaging host\",\"path\":\"/bin/cat\",\"type\":\"stdio\",\"allowed_extensions\":[\"some-extension at example.org\"]}");
-+
-+  start (test_data->session_handle,
-+         "org.example.testing",
-+         "some-extension at example.org",
-+         test_data->cancellable,
-+         start_cb,
-+         test_data);
-+}
-+
-+static void
-+create_session_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  TestData *test_data = data;
-+  g_autoptr(GError) error = NULL;
-+
-+  test_data->session_handle = create_session_finish (result, &error);
-+  g_assert_no_error (error);
-+  g_assert_nonnull (test_data->session_handle);
-+
-+  get_manifest (test_data->session_handle,
-+                "org.example.testing",
-+                "some-extension at example.org",
-+                test_data->cancellable,
-+                get_manifest_cb,
-+                test_data);
-+}
-+
-+void
-+test_web_extensions_basic (void)
-+{
-+  g_autoptr(GCancellable) cancellable = NULL;
-+  TestData test_data = { cancellable, NULL };
-+
-+  got_info = 0;
-+
-+  set_web_extensions_permissions ("yes");
-+  create_session (cancellable, create_session_cb, &test_data);
-+
-+  g_timeout_add (100, cancel_call, cancellable);
-+  while (!got_info)
-+    g_main_context_iteration (NULL, TRUE);
-+  g_free (test_data.session_handle);
-+}
-+
-+static void
-+start_bad_name_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  g_autoptr(GError) error = NULL;
-+  gboolean ret;
-+
-+  ret = start_finish (result, &error);
-+  g_assert_false (ret);
-+  g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
-+
-+  got_info++;
-+  g_main_context_wakeup (NULL);
-+}
-+
-+static void
-+create_session_bad_name_cb (GObject *object, GAsyncResult *result, gpointer data)
-+{
-+  TestData *test_data = data;
-+  g_autoptr(GError) error = NULL;
-+
-+  test_data->session_handle = create_session_finish (result, &error);
-+  g_assert_no_error (error);
-+  g_assert_nonnull (test_data->session_handle);
-+
-+  start (test_data->session_handle,
-+         test_data->server_name,
-+         "some-extension at example.org",
-+         test_data->cancellable,
-+         start_bad_name_cb,
-+         test_data);
-+}
-+
-+void
-+test_web_extensions_bad_name (void)
-+{
-+    const char *server_name[] = {
-+        "no-dashes",
-+        "../foo",
-+        "no_trailing_dot.",
-+    };
-+    int i;
-+
-+    for (i = 0; i < G_N_ELEMENTS (server_name); i++)
-+      {
-+        g_autoptr(GCancellable) cancellable = NULL;
-+        TestData test_data = { cancellable, NULL, server_name[i] };
-+
-+        got_info = 0;
-+        set_web_extensions_permissions ("yes");
-+        create_session (cancellable, create_session_bad_name_cb, &test_data);
-+
-+        g_timeout_add (100, cancel_call, cancellable);
-+        while (!got_info)
-+          g_main_context_iteration (NULL, TRUE);
-+        g_free (test_data.session_handle);
-+    }
-+}
-diff --git a/tests/web-extensions.h b/tests/web-extensions.h
-new file mode 100644
-index 0000000..0090184
---- /dev/null
-+++ b/tests/web-extensions.h
-@@ -0,0 +1,2 @@
-+void test_web_extensions_basic (void);
-+void test_web_extensions_bad_name (void);
diff --git a/debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch b/debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
new file mode 100644
index 0000000..8e4fc45
--- /dev/null
+++ b/debian/patches/xdp_validate_icon-Allow-sandboxing-of-the-validator-to-be.patch
@@ -0,0 +1,31 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Wed, 30 Oct 2024 17:41:39 +0000
+Subject: xdp_validate_icon: Allow sandboxing of the validator to be disabled
+
+OS distributions often compile packages and run their build-time tests
+in a chroot environment or an unprivileged container, and bubblewrap
+cannot usually work in either of those environments.
+
+Signed-off-by: Simon McVittie <smcv at debian.org>
+Bug: https://github.com/flatpak/xdg-desktop-portal/issues/1497
+Forwarded: https://github.com/flatpak/xdg-desktop-portal/pull/1498
+---
+ src/xdp-utils.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/src/xdp-utils.c b/src/xdp-utils.c
+index 8ecb84b..3fde49c 100644
+--- a/src/xdp-utils.c
++++ b/src/xdp-utils.c
+@@ -606,7 +606,10 @@ xdp_validate_icon (XdpSealedFd  *icon,
+ 
+   i = 0;
+   args[i++] = icon_validator;
+-  args[i++] = "--sandbox";
++
++  if (g_getenv ("XDP_VALIDATE_ICON_INSECURE") == NULL)
++    args[i++] = "--sandbox";
++
+   args[i++] = "--fd";
+   args[i++] = G_STRINGIFY (VALIDATOR_INPUT_FD);
+   args[i++] = "--ruleset";
diff --git a/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch b/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
new file mode 100644
index 0000000..c5c907b
--- /dev/null
+++ b/debian/patches/xdp_validate_icon-Assign-argument-indices-automatically.patch
@@ -0,0 +1,46 @@
+From: Simon McVittie <smcv at debian.org>
+Date: Wed, 30 Oct 2024 17:40:29 +0000
+Subject: xdp_validate_icon: Assign argument indices automatically
+
+Signed-off-by: Simon McVittie <smcv at debian.org>
+Bug: https://github.com/flatpak/xdg-desktop-portal/issues/1497
+Forwarded: https://github.com/flatpak/xdg-desktop-portal/pull/1498
+---
+ src/xdp-utils.c | 17 ++++++++++-------
+ 1 file changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/src/xdp-utils.c b/src/xdp-utils.c
+index 2219b36..8ecb84b 100644
+--- a/src/xdp-utils.c
++++ b/src/xdp-utils.c
+@@ -591,6 +591,7 @@ xdp_validate_icon (XdpSealedFd  *icon,
+   const char *icon_validator = LIBEXECDIR "/xdg-desktop-portal-validate-icon";
+   const char *args[7];
+   int size;
++  size_t i;
+   g_autofree char *output = NULL;
+   g_autoptr(GKeyFile) key_file = NULL;
+ 
+@@ -603,13 +604,15 @@ xdp_validate_icon (XdpSealedFd  *icon,
+       return FALSE;
+     }
+ 
+-  args[0] = icon_validator;
+-  args[1] = "--sandbox";
+-  args[2] = "--fd";
+-  args[3] = G_STRINGIFY (VALIDATOR_INPUT_FD);
+-  args[4] = "--ruleset";
+-  args[5] = icon_type_to_string (icon_type);
+-  args[6] = NULL;
++  i = 0;
++  args[i++] = icon_validator;
++  args[i++] = "--sandbox";
++  args[i++] = "--fd";
++  args[i++] = G_STRINGIFY (VALIDATOR_INPUT_FD);
++  args[i++] = "--ruleset";
++  args[i++] = icon_type_to_string (icon_type);
++  g_assert (i < G_N_ELEMENTS (args));
++  args[i++] = NULL;
+ 
+   output = xdp_spawn_full (args, xdp_sealed_fd_dup_fd (icon), VALIDATOR_INPUT_FD, &error);
+   if (!output)
diff --git a/debian/rules b/debian/rules
index 32e383e..9202559 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,6 +9,18 @@ built_binaries := $(shell dh_listpackages)
 
 CONFFLAGS :=
 
+ifneq ($(filter %-dev,$(built_binaries)),)
+CONFFLAGS += -Ddocumentation=enabled
+else
+CONFFLAGS += -Ddocumentation=disabled
+endif
+
+ifeq ($(filter nodoc,$(DEB_BUILD_PROFILES)),)
+CONFFLAGS += -Dman-pages=enabled
+else
+CONFFLAGS += -Dman-pages=disabled
+endif
+
 %:
 	dh $@ --buildsystem=meson
 
@@ -16,7 +28,7 @@ override_dh_auto_configure:
 	dh_auto_configure -- \
 		-Dauto_features=enabled \
 		-Dinstalled-tests=true \
-		-Dsandboxed-image-validation=true \
+		-Dsandboxed-image-validation=enabled \
 		$(CONFFLAGS)
 		$(NULL)
 
@@ -24,6 +36,7 @@ override_dh_auto_test:
 ifeq ($(filter nocheck,$(DEB_BUILD_OPTIONS)),)
 	G_MESSAGES_DEBUG=all \
 	TEST_IN_CI=1 \
+	XDP_VALIDATE_ICON_INSECURE=1 \
 	dh_auto_test --no-parallel
 endif
 
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
index 5241034..0c22dc4 100644
--- a/debian/salsa-ci.yml
+++ b/debian/salsa-ci.yml
@@ -1,7 +1,3 @@
 include:
   - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
   - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
-
-variables:
-  RELEASE: 'unstable'
-  SALSA_CI_LINTIAN_SUPPRESS_TAGS: 'bad-distribution-in-changes-file,mail-address-loops-or-bounces'
diff --git a/debian/watch b/debian/watch
index 28c5196..8586049 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,9 +1,10 @@
 version=4
-# Upstream releases official Autotools 'make dist' tarballs, so we use
-# those in preference to git tags
+# Upstream releases official tarballs, so we use those in preference to
+# git tags
 opts="\
     compression=xz, \
-    dversionmangle=s/\+(?:git)?[0-9]*(?:\+g[0-9a-f]*)//, \
+    dversionmangle=s/\+(?:git)?[0-9]*(?:\+g[0-9a-f]*)?(?:[+~](?:dfsg|ds)[0-9]*)?//, \
     downloadurlmangle=s#/tag/#/download/#;s#(v?@ANY_VERSION@)$#$1/@PACKAGE at -$2.tar.xz#, \
-    filenamemangle=s#v?@ANY_VERSION@#@PACKAGE at -$1.tar.xz#" \
+    filenamemangle=s#v?@ANY_VERSION@#@PACKAGE at -$1.tar.xz#, \
+    repacksuffix=+ds" \
 https://github.com/flatpak/@PACKAGE@/tags .*/releases/tag/v?@ANY_VERSION@
diff --git a/debian/xdg-desktop-portal-dev.doc-base b/debian/xdg-desktop-portal-dev.doc-base
index bcbb95b..e3e7ad3 100644
--- a/debian/xdg-desktop-portal-dev.doc-base
+++ b/debian/xdg-desktop-portal-dev.doc-base
@@ -4,5 +4,5 @@ Author: Matthias Clasen
 Section: Programming
 
 Format: HTML
-Index: /usr/share/doc/xdg-desktop-portal/portal-docs.html
-Files: /usr/share/doc/xdg-desktop-portal/portal-docs.html /usr/share/doc/xdg-desktop-portal/docbook.css
+Index: /usr/share/doc/xdg-desktop-portal-dev/html/index.html
+Files: /usr/share/doc/xdg-desktop-portal-dev/html/*.html
diff --git a/debian/xdg-desktop-portal-dev.docs b/debian/xdg-desktop-portal-dev.docs
new file mode 100644
index 0000000..28fcd6c
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.docs
@@ -0,0 +1 @@
+obj-*/doc/html
diff --git a/debian/xdg-desktop-portal-dev.install b/debian/xdg-desktop-portal-dev.install
index 62e5ec5..b56a12e 100644
--- a/debian/xdg-desktop-portal-dev.install
+++ b/debian/xdg-desktop-portal-dev.install
@@ -1,4 +1,2 @@
 usr/share/dbus-1/interfaces
-usr/share/doc/xdg-desktop-portal/docbook.css
-usr/share/doc/xdg-desktop-portal/portal-docs.html
 usr/share/pkgconfig/xdg-desktop-portal.pc
diff --git a/debian/xdg-desktop-portal-dev.links b/debian/xdg-desktop-portal-dev.links
new file mode 100644
index 0000000..68ca494
--- /dev/null
+++ b/debian/xdg-desktop-portal-dev.links
@@ -0,0 +1 @@
+usr/share/doc/xdg-desktop-portal-dev/html usr/share/doc/xdg-desktop-portal/html
diff --git a/debian/xdg-desktop-portal.lintian-overrides b/debian/xdg-desktop-portal.lintian-overrides
deleted file mode 100644
index b6add39..0000000
--- a/debian/xdg-desktop-portal.lintian-overrides
+++ /dev/null
@@ -1,2 +0,0 @@
-# https://bugs.debian.org/1031037
-no-manual-page [usr/libexec/*]



More information about the Neon-commits mailing list