├── .github └── workflows │ ├── build.yml │ ├── flatpak.yml │ └── pages.yml ├── .gitignore ├── COPYING ├── NEWS ├── README.md ├── build-aux ├── build.sh ├── org.gnome.PortalTest.Gtk3.json ├── org.gnome.PortalTest.Gtk4.json ├── org.gnome.PortalTest.Qt5.json └── org.gnome.PortalTest.Qt6.json ├── doc ├── favicon-128x128.png ├── favicon-180x180.png ├── favicon-192x192.png ├── favicon-32x32.png ├── libportal.md ├── libportal.svg ├── libportal.toml.in ├── meson.build ├── release-checklist.md └── urlmap.js ├── libportal ├── TODO ├── account.c ├── account.h ├── background.c ├── background.h ├── camera.c ├── camera.h ├── dynamic-launcher.c ├── dynamic-launcher.h ├── email.c ├── email.h ├── filechooser.c ├── filechooser.h ├── glib-backports.h ├── inhibit.c ├── inhibit.h ├── inputcapture-pointerbarrier.c ├── inputcapture-pointerbarrier.h ├── inputcapture-private.h ├── inputcapture-zone.c ├── inputcapture-zone.h ├── inputcapture.c ├── inputcapture.h ├── location.c ├── location.h ├── meson.build ├── notification.c ├── notification.h ├── openuri.c ├── openuri.h ├── parent-private.h ├── parent.c ├── parent.h ├── portal-enums.c.template ├── portal-enums.h.template ├── portal-gtk3.c ├── portal-gtk3.h ├── portal-gtk4.c ├── portal-gtk4.h ├── portal-helpers.h ├── portal-private.h ├── portal-qt5.cpp ├── portal-qt5.h ├── portal-qt6.cpp ├── portal-qt6.h ├── portal.c ├── portal.h ├── print.c ├── print.h ├── remote.c ├── remote.h ├── screenshot.c ├── screenshot.h ├── session-private.h ├── session.c ├── session.h ├── settings-private.h ├── settings.c ├── settings.h ├── spawn.c ├── spawn.h ├── trash.c ├── trash.h ├── types.h ├── updates.c ├── updates.h ├── wallpaper.c └── wallpaper.h ├── meson.build ├── meson_options.txt ├── portal-test ├── gtk3 │ ├── main.c │ ├── meson.build │ ├── org.gnome.PortalTest.Gtk3.desktop │ ├── org.gnome.PortalTest.Gtk3.service │ ├── portal-linking-test.c │ ├── portal-test-app.c │ ├── portal-test-app.h │ ├── portal-test-win.c │ ├── portal-test-win.h │ ├── portal-test-win.ui │ ├── portal-test.gresource.xml │ └── test.txt ├── gtk4 │ ├── application.js │ ├── main.js │ ├── meson.build │ ├── org.gnome.PortalTest.Gtk4.data.gresource.xml │ ├── org.gnome.PortalTest.Gtk4.desktop │ ├── org.gnome.PortalTest.Gtk4.in │ ├── org.gnome.PortalTest.Gtk4.service │ ├── org.gnome.PortalTest.Gtk4.src.gresource.xml │ ├── portal-linking-test.c │ ├── test.txt │ ├── window.js │ └── window.ui ├── meson.build ├── qt5 │ ├── main.cpp │ ├── meson.build │ ├── portal-test-qt.cpp │ ├── portal-test-qt.h │ └── portal-test-qt.ui └── qt6 │ ├── main.cpp │ ├── meson.build │ ├── portal-test-qt.cpp │ ├── portal-test-qt.h │ └── portal-test-qt.ui ├── subprojects └── gi-docgen.wrap └── tests ├── gir-testenv.sh ├── meson.build ├── pyportaltest ├── __init__.py ├── templates │ ├── __init__.py │ ├── inputcapture.py │ ├── notification.py │ ├── remotedesktop.py │ ├── screencast.py │ └── wallpaper.py ├── test_inputcapture.py ├── test_notification.py ├── test_remotedesktop.py ├── test_screencast.py └── test_wallpaper.py ├── qt5 ├── meson.build ├── test.cpp └── test.h └── qt6 ├── meson.build ├── test.cpp └── test.h /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: libportal CI 2 | 3 | env: 4 | DEBIAN_FRONTEND: noninteractive 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | jobs: 15 | ubuntu: 16 | name: Ubuntu 17 | runs-on: ubuntu-latest 18 | container: ubuntu:${{ matrix.ubuntu-version }} 19 | strategy: 20 | matrix: 21 | ubuntu-version: ['22.04', '24.04'] 22 | compiler: ['gcc', 'clang'] 23 | 24 | env: 25 | CC: ${{ matrix.compiler }} 26 | 27 | steps: 28 | - name: Install dependencies 29 | run: | 30 | echo "$HOME/.local/bin" >> $GITHUB_PATH 31 | apt-get update --quiet 32 | apt-get install --quiet -y \ 33 | ${{ matrix.compiler }} \ 34 | dbus \ 35 | gettext \ 36 | git \ 37 | gi-docgen \ 38 | libgirepository1.0-dev \ 39 | libglib2.0 \ 40 | libgtk-3-dev \ 41 | libgtk-4-dev \ 42 | libqt5x11extras5-dev \ 43 | meson \ 44 | python3-dbusmock \ 45 | python3-pytest \ 46 | qtbase5-dev \ 47 | qt6-base-dev \ 48 | qt6-base-private-dev \ 49 | valac 50 | - name: Check out libportal 51 | uses: actions/checkout@v4 52 | - name: Fix Git ownership 53 | run: | 54 | echo $GITHUB_WORKSPACE 55 | git config --global --add safe.directory $GITHUB_WORKSPACE 56 | git status 57 | - name: Configure libportal 58 | run: meson setup --prefix=/usr _build -Dbackend-gtk3=enabled -Dbackend-gtk4=enabled -Dbackend-qt5=enabled -Dbackend-qt6=enabled 59 | - name: Build libportal 60 | run: ninja -C_build 61 | - name: Run libportal tests 62 | working-directory: _build 63 | run: meson test --verbose --print-errorlogs 64 | - name: Generate dist tarball 65 | working-directory: _build 66 | run: meson dist 67 | - name: Upload test logs 68 | uses: actions/upload-artifact@v4 69 | if: success() || failure() 70 | with: 71 | name: test logs (ubuntu ${{ matrix.ubuntu-version }} ${{ matrix.compiler }}) 72 | path: | 73 | tests/*.log 74 | test-*.log 75 | installed-test-logs/ 76 | _build/meson-logs/testlog.txt 77 | _build/meson-dist/ 78 | 79 | fedora: 80 | name: Fedora 81 | runs-on: ubuntu-latest 82 | container: fedora:${{ matrix.fedora-version }} 83 | strategy: 84 | matrix: 85 | fedora-version: ['39', '40'] 86 | compiler: ['gcc', 'clang'] 87 | 88 | env: 89 | CC: ${{ matrix.compiler }} 90 | 91 | steps: 92 | - name: Install dependencies 93 | run: | 94 | dnf install --quiet -y \ 95 | ${{ matrix.compiler }} \ 96 | git \ 97 | gi-docgen \ 98 | gobject-introspection-devel \ 99 | gtk3-devel \ 100 | gtk4-devel \ 101 | meson \ 102 | python3-pytest \ 103 | python3-dbusmock \ 104 | qt5-qtbase-devel \ 105 | qt5-qtx11extras-devel \ 106 | qt6-qtbase-devel \ 107 | qt6-qtbase-private-devel \ 108 | vala 109 | - name: Check out libportal 110 | uses: actions/checkout@v4 111 | - name: Fix Git ownership 112 | run: | 113 | echo $GITHUB_WORKSPACE 114 | git config --global --add safe.directory $GITHUB_WORKSPACE 115 | git status 116 | - name: Configure libportal 117 | run: meson setup --prefix=/usr _build -Dbackend-gtk3=enabled -Dbackend-gtk4=enabled -Dbackend-qt5=enabled -Dbackend-qt6=enabled 118 | - name: Build libportal 119 | run: ninja -C_build 120 | - name: Run libportal tests 121 | working-directory: _build 122 | run: meson test --verbose --print-errorlogs 123 | - name: Generate dist tarball 124 | working-directory: _build 125 | run: meson dist 126 | - name: Upload test logs 127 | uses: actions/upload-artifact@v4 128 | if: success() || failure() 129 | with: 130 | name: test logs (fedora ${{ matrix.fedora-version }} ${{ matrix.compiler }}) 131 | path: | 132 | tests/*.log 133 | test-*.log 134 | installed-test-logs/ 135 | _build/meson-logs/testlog.txt 136 | _build/meson-dist/ 137 | 138 | abi-check: 139 | name: ABI check 140 | runs-on: ubuntu-latest 141 | container: fedora:latest 142 | env: 143 | LAST_ABI_BREAK: "467a397fd7996557f837cdc26ac07c01c62810e5" 144 | 145 | steps: 146 | - name: Install dependencies 147 | run: | 148 | dnf install -y meson gcc gobject-introspection-devel gtk3-devel gtk4-devel qt5-qtbase-devel qt5-qtx11extras-devel qt6-qtbase-devel qt6-qtbase-private-devel git libabigail 149 | - name: Install check-abi 150 | run: | 151 | curl https://gitlab.freedesktop.org/hadess/check-abi/-/raw/main/contrib/check-abi-fedora.sh | bash 152 | rm -rf check-abi/ 153 | - name: Check out libportal 154 | uses: actions/checkout@v4 155 | with: 156 | fetch-depth: 0 157 | - name: Work around git safe directory check 158 | run: git config --global --add safe.directory $GITHUB_WORKSPACE 159 | - name: Run ABI check 160 | run: check-abi --old-parameters="-Dvapi=false -Ddocs=false -Dintrospection=false" --new-parameters="-Dvapi=false -Ddocs=false -Dtests=false -Dintrospection=false" ${LAST_ABI_BREAK} $GITHUB_SHA 161 | -------------------------------------------------------------------------------- /.github/workflows/flatpak.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | name: Flatpak Portal Test App 4 | 5 | on: 6 | push: 7 | paths-ignore: ['**.md'] 8 | branches: [main] 9 | pull_request: 10 | paths-ignore: ['**.md'] 11 | branches: [main] 12 | 13 | jobs: 14 | build-flatpak-gtk3: 15 | name: GTK3 16 | runs-on: ubuntu-latest 17 | container: 18 | image: bilelmoussaoui/flatpak-github-actions:gnome-46 19 | options: --privileged 20 | steps: 21 | - name: Checkout 22 | uses: actions/checkout@v3 23 | 24 | - name: Build GTK3 portal test 25 | uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v6 26 | with: 27 | bundle: portal-test-gtk3.flatpak 28 | manifest-path: build-aux/org.gnome.PortalTest.Gtk3.json 29 | cache-key: gtk3-${{ github.sha }} 30 | 31 | build-flatpak-gtk4: 32 | name: GTK4 33 | runs-on: ubuntu-latest 34 | container: 35 | image: bilelmoussaoui/flatpak-github-actions:gnome-46 36 | options: --privileged 37 | steps: 38 | - name: Checkout 39 | uses: actions/checkout@v3 40 | 41 | - name: Build GTK4 portal test 42 | uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v6 43 | with: 44 | bundle: portal-test-gtk4.flatpak 45 | manifest-path: build-aux/org.gnome.PortalTest.Gtk4.json 46 | cache-key: gtk4-${{ github.sha }} 47 | 48 | build-flatpak-qt5: 49 | name: Qt5 50 | runs-on: ubuntu-latest 51 | container: 52 | image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08 53 | options: --privileged 54 | steps: 55 | - name: Checkout 56 | uses: actions/checkout@v3 57 | 58 | - name: Build Qt5 portal test 59 | uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v6 60 | with: 61 | bundle: portal-test-qt5.flatpak 62 | manifest-path: build-aux/org.gnome.PortalTest.Qt5.json 63 | cache-key: qt5-${{ github.sha }} 64 | 65 | build-flatpak-qt6: 66 | name: Qt6 67 | runs-on: ubuntu-latest 68 | container: 69 | image: bilelmoussaoui/flatpak-github-actions:kde-6.7 70 | options: --privileged 71 | steps: 72 | - name: Checkout 73 | uses: actions/checkout@v3 74 | 75 | - name: Build Qt6 portal test 76 | uses: bilelmoussaoui/flatpak-github-actions/flatpak-builder@v6 77 | with: 78 | bundle: portal-test-qt6.flatpak 79 | manifest-path: build-aux/org.gnome.PortalTest.Qt6.json 80 | cache-key: qt6-${{ github.sha }} 81 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: 6 | contents: read 7 | pages: write 8 | id-token: write 9 | 10 | concurrency: 11 | group: "pages" 12 | cancel-in-progress: false 13 | 14 | jobs: 15 | build: 16 | runs-on: ubuntu-latest 17 | container: 18 | image: fedora:latest 19 | 20 | steps: 21 | - name: Install dependencies 22 | run: | 23 | dnf install -y \ 24 | gcc \ 25 | gi-docgen \ 26 | git \ 27 | gobject-introspection-devel \ 28 | meson \ 29 | python3-pytest \ 30 | python3-dbusmock 31 | 32 | - name: Check out libportal 33 | uses: actions/checkout@v4 34 | 35 | - name: Configure libportal 36 | run: meson setup --prefix=/usr builddir -Dtests=false -Dvapi=false 37 | 38 | - name: Build libportal 39 | run: ninja -C builddir doc/libportal-1 40 | 41 | - name: Prepare docs 42 | working-directory: builddir/doc 43 | run: | 44 | mv ./libportal-1 ../../_site 45 | 46 | - name: Upload artifact 47 | uses: actions/upload-pages-artifact@v3 48 | 49 | # Deployment job 50 | deploy: 51 | needs: build 52 | runs-on: ubuntu-latest 53 | if: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/main') }} 54 | environment: 55 | name: github-pages 56 | url: ${{ steps.deployment.outputs.page_url }} 57 | 58 | steps: 59 | - name: Deploy to GitHub Pages 60 | id: deployment 61 | uses: actions/deploy-pages@v4 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.flatpak-builder/ 2 | /_build/ 3 | __pycache__/ 4 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Changes in 0.9.2, yyyy-mm-dd 2 | ============================ 3 | 4 | Not yet released. 5 | 6 | Changes in 0.9.1, 2025-02-12 7 | ============================ 8 | 9 | Dependencies: 10 | 11 | - Meson 0.55.0 is required 12 | 13 | Bug fixes: 14 | 15 | - Fix memory management in the Input Capture portal code (#169, #190) 16 | - Correct the type used for GObject signal connections (#184) 17 | - Remove wrong `(closure)` annotations, fixing GObject-Introspection warnings 18 | (#182) 19 | - Don't require a C++ compiler for the build architecture (#181) 20 | - Fix Meson warnings (#181) 21 | - Consistently use `#pragma once` (#192) 22 | - Initialize all g_autoptr variables (#180) 23 | 24 | Changes in 0.9.0, 21-12-2024 25 | ========================== 26 | 27 | Dependencies: 28 | 29 | - GLib 2.72 or higher is now required 30 | 31 | Features: 32 | 33 | - Introduce support for the Notification v2 portal version 34 | 35 | Bug fixes: 36 | 37 | - Fix a file descriptor leak in the Mail portal code 38 | - Fix some minor memory leaks 39 | 40 | Changes in 0.8.1, 04-09-2024 41 | ========================== 42 | 43 | - Fix a regression in the Remote Desktop where it wouldn't work with the 44 | ScreenCast portal correctly. 45 | - Use non-deprecated functions in the GTK4 code 46 | - Run tests in CI so we catch regressions earlier 47 | - Make Qt tests use QTEST_GUILESS_MAIN 48 | - Fix an Input Capture test 49 | 50 | Changes in 0.8.0, 02-09-2024 51 | ========================== 52 | 53 | - Add API to allow for persistence on RemoteDesktop sessions 54 | - Implement support for the Input Capture portal 55 | - Add support for Qt 6 56 | - Support xdg-foreign with Qt 6 57 | - Fix screencasting on wlroots-based compositors 58 | 59 | 60 | Changes in 0.7.1, 09-09-2023 61 | ========================== 62 | 63 | - Restore ability to call g_object_new (XDP_TYPE_PORTAL, ...) 64 | 65 | Changes in 0.7, 06-09-2023 66 | ========================== 67 | 68 | - Add support for the new SetStatus() method of the Background portal 69 | - Add support for the new ConnectToEIS() method of the Remote Desktop portal 70 | - Improve unit and integration tests 71 | - Documentation improvements 72 | - CI improvements 73 | 74 | Changes in 0.6, 21-03-2022 75 | ========================== 76 | 77 | - New portal support: Dynamic launcher 78 | - Add API for checking for flatpak/snap sandbox 79 | - Fix a bug where the callback setup by libportal for a GCancellable was not 80 | properly canceled in case a portal method call was not successful, which can 81 | lead to a double free seg fault 82 | - libportal-qt: Add convenient functions to better deal with GVariants 83 | - libportal-qt: Use a global instance of XdpPortal object 84 | - libportal-qt: make filechooserFilterToGVariant() public 85 | - camera: Use correct variant for is_camera_present() 86 | - portal-test-gtk3: Fix incorrect paths used in tests 87 | - Documentation improvements 88 | - CI improvements 89 | 90 | Changes in 0.5, 21-12-2021 91 | ========================== 92 | 93 | - Relicence to LGPL 3.0 94 | - Fix a refcounting error in xdp_parent_free 95 | - location: Fix location-updated signature 96 | - remote: Add cursor mode 97 | - remote: Support virtual screens 98 | - remote: Support persistent sessions 99 | - Rename qt backend to qt5 100 | - Install separate libraries: libportal-gtk3, libportal-gtk4, libportal-qt5 101 | - Add gobject-introspection support 102 | - Add vala support 103 | - Add a GTK4 portal test app, using gjs 104 | - Build documentation using gi-docgen 105 | 106 | Changes in 0.4 107 | ============== 108 | 109 | - Make GTK4 support work with GTK 4.0 110 | - Qt5 support 111 | - OpenURI: Support write access 112 | - Build fixes 113 | - Add more tests 114 | - Require GLib 2.58 115 | 116 | Changes in 0.3 117 | ============== 118 | 119 | - Clean up includes 120 | - Future-proof the API 121 | - Test and fix update monitor APIs 122 | 123 | Changes in 0.2 124 | ============== 125 | 126 | - Build a portal-test application if you specify -Dbuild-portal-test=true 127 | - The portal-test app comes with a flatpak build script for ease of testing 128 | - The OpenURI call has gained an 'ask' argument 129 | - 130 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | libportal - Flatpak portal library 2 | ================================== 3 | 4 | libportal provides GIO-style async APIs for most Flatpak portals. You can find 5 | the documentation [here](https://flatpak.github.io/libportal/). 6 | 7 | ## Getting started 8 | 9 | `libportal` uses Meson to build its projects. To install Meson on your system, 10 | follow the [Getting Meson instructions][1]. If your system is missing a 11 | dependency, Meson will tell you which one. How you install your missing 12 | dependencies is up to you. 13 | 14 | ### Build libportal 15 | 16 | The first time you build libportal, give `meson` a directory to build into; we 17 | recommend `_build`: 18 | 19 | ``` 20 | meson _build 21 | ``` 22 | 23 | Then use `ninja` to build the project, pointing it to your build directory: 24 | 25 | ``` 26 | ninja -C _build 27 | ``` 28 | 29 | For subsequent builds, you only need to use the `ninja -C _build` command. 30 | 31 | ### Passing options 32 | 33 | libportal includes [Meson build options][2] for components that can optionally 34 | be built. Run `meson configure` to see all available options or, 35 | after first running `meson _build`, view available options and their current 36 | values with: 37 | 38 | ``` 39 | meson configure _build 40 | ``` 41 | 42 | To change an option, re-configure the project: 43 | 44 | ``` 45 | meson configure _build -Dportal-tests=true 46 | ``` 47 | 48 | You can also pass in options right from the start, e.g. with: 49 | 50 | ``` 51 | meson _build -Dportal-tests=true 52 | ``` 53 | 54 | Then build: 55 | 56 | ``` 57 | ninja -C _build 58 | ``` 59 | 60 | ## Optional components 61 | 62 | ### `portal-tests` 63 | 64 | To generate test binaries, set the `portal-tests` option to `true`, 65 | e.g. `-Dportal-tests=true`, to build the portal tests for the backend 66 | built. Then run the desired test binary, e.g.: 67 | 68 | ``` 69 | ./_build/portal-test/gtk3/portal-test-gtk3 70 | ``` 71 | 72 | or 73 | 74 | ``` 75 | ./_build/portal-test/qt5/portal-test-qt5 76 | ``` 77 | 78 | [1]: https://mesonbuild.com/Getting-meson.html 79 | [2]: https://mesonbuild.com/Build-options.html#build-options 80 | -------------------------------------------------------------------------------- /build-aux/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | TOP_DIR=`dirname $0`/.. 6 | OLD_DIR=`pwd` 7 | 8 | cd "$TOP_DIR" 9 | 10 | for backend in Gtk3 Gtk4 Qt5 Qt6; do 11 | flatpak-builder --force-clean --ccache --repo=_build/repo --install --user "_build/app-$backend" "build-aux/org.gnome.PortalTest.${backend}.json" 12 | done 13 | 14 | cd "$OLD_DIR" 15 | -------------------------------------------------------------------------------- /build-aux/org.gnome.PortalTest.Gtk3.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id": "org.gnome.PortalTest.Gtk3", 3 | "runtime": "org.gnome.Platform", 4 | "runtime-version": "47", 5 | "sdk": "org.gnome.Sdk", 6 | "command": "portal-test-gtk3", 7 | "finish-args": [ 8 | "--socket=wayland", 9 | "--socket=x11", 10 | "--socket=pulseaudio" 11 | ], 12 | "modules": [ 13 | { 14 | "name": "gtk3", 15 | "disabled": true, 16 | "buildsystem": "meson", 17 | "builddir": true, 18 | "config-opts": [ 19 | "-Dgtk_doc=false" 20 | ], 21 | "sources": [ 22 | { 23 | "type": "git", 24 | "url": "https://gitlab.gnome.org/GNOME/gtk.git", 25 | "branch": "gtk-3-24" 26 | } 27 | ] 28 | }, 29 | { 30 | "name": "portal-test-gtk3", 31 | "buildsystem": "meson", 32 | "builddir": true, 33 | "config-opts": [ 34 | "-Dbackend-gtk3=enabled", 35 | "-Dbackend-gtk4=disabled", 36 | "-Dbackend-qt5=disabled", 37 | "-Dbackend-qt6=disabled", 38 | "-Dportal-tests=true", 39 | "-Ddocs=false" 40 | ], 41 | "sources": [ 42 | { 43 | "type": "dir", 44 | "path": "../" 45 | } 46 | ] 47 | } 48 | ] 49 | } 50 | -------------------------------------------------------------------------------- /build-aux/org.gnome.PortalTest.Gtk4.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id": "org.gnome.PortalTest.Gtk4", 3 | "runtime": "org.gnome.Platform", 4 | "runtime-version": "47", 5 | "sdk": "org.gnome.Sdk", 6 | "command": "org.gnome.PortalTest.Gtk4", 7 | "finish-args": [ 8 | "--device=dri", 9 | "--socket=wayland", 10 | "--socket=x11", 11 | "--socket=pulseaudio" 12 | ], 13 | "modules": [ 14 | { 15 | "name": "portal-test-gtk4", 16 | "buildsystem": "meson", 17 | "builddir": true, 18 | "config-opts": [ 19 | "-Dbackend-gtk3=disabled", 20 | "-Dbackend-gtk4=enabled", 21 | "-Dbackend-qt5=disabled", 22 | "-Dbackend-qt6=disabled", 23 | "-Dportal-tests=true", 24 | "-Ddocs=false" 25 | ], 26 | "sources": [ 27 | { 28 | "type": "dir", 29 | "path": "../" 30 | } 31 | ] 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /build-aux/org.gnome.PortalTest.Qt5.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id": "org.gnome.PortalTest.Qt5", 3 | "runtime": "org.kde.Platform", 4 | "runtime-version": "5.15-23.08", 5 | "sdk": "org.kde.Sdk", 6 | "command": "portal-test-qt5", 7 | "finish-args": [ 8 | "--socket=wayland", 9 | "--socket=x11", 10 | "--socket=pulseaudio" 11 | ], 12 | "modules": [ 13 | { 14 | "name": "portal-test-qt5", 15 | "buildsystem": "meson", 16 | "builddir": true, 17 | "config-opts": [ 18 | "-Dbackend-gtk3=disabled", 19 | "-Dbackend-gtk4=disabled", 20 | "-Dbackend-qt5=enabled", 21 | "-Dbackend-qt6=disabled", 22 | "-Dportal-tests=true", 23 | "-Dintrospection=false", 24 | "-Dvapi=false", 25 | "-Ddocs=false" 26 | ], 27 | "sources": [ 28 | { 29 | "type": "dir", 30 | "path": "../" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /build-aux/org.gnome.PortalTest.Qt6.json: -------------------------------------------------------------------------------- 1 | { 2 | "app-id": "org.gnome.PortalTest.Qt6", 3 | "runtime": "org.kde.Platform", 4 | "runtime-version": "6.7", 5 | "sdk": "org.kde.Sdk", 6 | "command": "portal-test-qt6", 7 | "finish-args": [ 8 | "--socket=wayland", 9 | "--socket=x11", 10 | "--socket=pulseaudio" 11 | ], 12 | "modules": [ 13 | { 14 | "name": "portal-test-qt6", 15 | "buildsystem": "meson", 16 | "builddir": true, 17 | "config-opts": [ 18 | "-Dbackend-gtk3=disabled", 19 | "-Dbackend-gtk4=disabled", 20 | "-Dbackend-qt5=disabled", 21 | "-Dbackend-qt6=enabled", 22 | "-Dportal-tests=true", 23 | "-Dintrospection=false", 24 | "-Dvapi=false", 25 | "-Ddocs=false" 26 | ], 27 | "sources": [ 28 | { 29 | "type": "dir", 30 | "path": "../" 31 | } 32 | ] 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /doc/favicon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatpak/libportal/796053d2eebe4532aad6bd3fd80cdf3b197806ec/doc/favicon-128x128.png -------------------------------------------------------------------------------- /doc/favicon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatpak/libportal/796053d2eebe4532aad6bd3fd80cdf3b197806ec/doc/favicon-180x180.png -------------------------------------------------------------------------------- /doc/favicon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatpak/libportal/796053d2eebe4532aad6bd3fd80cdf3b197806ec/doc/favicon-192x192.png -------------------------------------------------------------------------------- /doc/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flatpak/libportal/796053d2eebe4532aad6bd3fd80cdf3b197806ec/doc/favicon-32x32.png -------------------------------------------------------------------------------- /doc/libportal.md: -------------------------------------------------------------------------------- 1 | Title: libportal Reference Manual 2 | Slug: reference-manual 3 | 4 | # Portals 5 | 6 | libportal is a library that provides GIO-style async API wrappers 7 | for the D-Bus portal APIs in xdg-desktop-portal. 8 | 9 | Where possible, applications should prefer to use existing library 10 | APIs that have portal support. For example, a GTK application should 11 | use [class@Gtk.FileChooserNative] instead of [method@Portal.open_file]. 12 | 13 | Some portal interfaces are not covered in libportal, since 14 | they already have perfectly adequate APIs in GLib (which libportal depends on anyway). 15 | 16 | - NetworkMonitor: Use [iface@Gio.NetworkMonitor] 17 | - ProxyResolver: Use [iface@Gio.ProxyResolver] 18 | - Settings: Use a plain [class@Gio.DBusProxy] 19 | - GameMode: Not currently covered 20 | - Secrets: Not currently covered 21 | 22 | ## Accounts 23 | 24 | The Accounts portal lets applications query basic information about 25 | the user, such as user ID, name and avatar picture. 26 | 27 | See [method@Portal.get_user_information]. 28 | 29 | The underlying D-Bus interface is [org.freedesktop.portal.Account](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Account). 30 | 31 | ## Background 32 | 33 | The Background portal lets applications request background permissions 34 | such as enabling autostart. 35 | 36 | See [method@Portal.request_background]. 37 | 38 | The underlying D-Bus interface is [org.freedesktop.portal.Background](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Background). 39 | 40 | ## Camera 41 | 42 | The Camera portal lets applications access camera devices and open [PipeWire][pipewire] remotes for them. 43 | 44 | To test if the Camera portal is available, you can use [method@Portal.is_camera_present]. 45 | 46 | See [method@Portal.access_camera]. 47 | 48 | The underlying D-Bus interface is [org.freedesktop.portal.Camera](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Camera). 49 | 50 | ## Email 51 | 52 | The Email portal lets applications send email, by prompting 53 | the user to compose a message. The email may already have 54 | an address, subject, body or attachments. 55 | 56 | See [method@Portal.compose_email]. 57 | 58 | The underlying D-Bus interface is [org.freedesktop.portal.Email](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Email). 59 | 60 | ## File 61 | 62 | The File portal lets applications ask the user for access to 63 | files outside the sandbox, by presenting a file chooser dialog. 64 | 65 | The selected files will be made accessible to the application 66 | via the document portal, and the returned URI will point 67 | into the document portal fuse filesystem in `/run/user/$UID/doc/`. 68 | 69 | See [method@Portal.open_file], [method@Portal.save_file], and [method@Portal.save_files]. 70 | 71 | The underlying D-Bus interface is [org.freedesktop.portal.FileChooser](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.FileChooser). 72 | 73 | ## Session 74 | 75 | The Session portal lets applications inhibit certain login session 76 | state changes, and be informed about the impending end of the 77 | session. 78 | 79 | A typical use for this functionality is to prevent the session 80 | from locking while a video is playing. 81 | 82 | See [method@Portal.session_inhibit], and [method@Portal.session_monitor_start]. 83 | 84 | The underlying D-Bus interface is [org.freedesktop.portal.Inhibit](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Inhibit). 85 | 86 | ## Location 87 | 88 | The Access portal lets app access to location information. 89 | 90 | Location monitoring makes location information available 91 | via the [signal@Portal::location-updated] signal. 92 | 93 | See [method@Portal.location_monitor_start]. 94 | 95 | The underlying D-Bus interface is [org.freedesktop.portal.Location](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Location). 96 | 97 | ## Notification 98 | 99 | The Notification portal lets applications send desktop notifications. 100 | 101 | See [method@Portal.add_notification]. 102 | 103 | The underlying D-Bus interface is [org.freedesktop.portal.Notification](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Notification). 104 | 105 | ## Open URI 106 | 107 | The Open URI portal lets applications open URIs in external handlers. 108 | A typical example is to open a pdf file in a document viewer. 109 | 110 | See [method@Portal.open_uri], and [method@Portal.open_directory]. 111 | 112 | The underlying D-Bus interface is [org.freedesktop.portal.OpenURI](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.OpenURI). 113 | 114 | ## Print 115 | 116 | The Print portal lets applications send documents to a printer. 117 | 118 | See [method@Portal.prepare_print], and [method@Portal.print_file]. 119 | 120 | The underlying D-Bus interface is [org.freedesktop.portal.Print](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Print). 121 | 122 | ## Screencast 123 | 124 | The Screencast portal lets applications create screencast sessions. 125 | 126 | A screencast session makes the content of a monitor or window 127 | available as a [PipeWire][pipewire] stream. 128 | 129 | See [method@Portal.create_screencast_session]. 130 | 131 | The underlying D-Bus interface is [org.freedesktop.portal.ScreenCast](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.ScreenCast). 132 | 133 | ## Remote Desktop 134 | 135 | The Remote Desktop portal allows remote control of a session. 136 | 137 | A remote desktop session allows to inject events into the input stream. 138 | 139 | See [method@Portal.create_remote_desktop_session]. 140 | 141 | The underlying D-Bus interface is [org.freedesktop.portal.RemoteDesktop](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.RemoteDesktop). 142 | 143 | ## Screenshot 144 | 145 | The Screenshot portal allows applications to take screenshots or pick colors. 146 | 147 | See [method@Portal.take_screenshot], and [method@Portal.pick_color]. 148 | 149 | The underlying D-Bus interface is [org.freedesktop.portal.Screenshot](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Screenshot). 150 | 151 | ## Spawn 152 | 153 | The Spawn portal lets applications spawn a process in another 154 | copy of their sandbox. 155 | 156 | To monitor spawned processes, use the [signal@Portal::spawn-exited] 157 | signal. 158 | 159 | See [method@Portal.spawn]. 160 | 161 | The underlying D-Bus interface is [org.freedesktop.portal.Flatpak](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Flatpak). 162 | 163 | ## Trash 164 | 165 | The Trash portal lets applications send a file to the trash can. 166 | 167 | See [method@Portal.trash_file]. 168 | 169 | The underlying D-Bus interface is [org.freedesktop.portal.Trash](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Trash). 170 | 171 | ## Updates 172 | 173 | The Updates portal lets applications be informed about available 174 | software updates (for themselves) and install those updates. 175 | 176 | See [method@Portal.update_install]. 177 | 178 | The underlying D-Bus interface is [org.freedesktop.portal.Flatpak](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Flatpak). 179 | 180 | ## Wallpaper 181 | 182 | The Wallpaper portal lets applications set desktop backgrounds. 183 | 184 | See [method@Portal.set_wallpaper]. 185 | 186 | The underlying D-Bus interface is [org.freedesktop.portal.Wallpaper](https://flatpak.github.io/xdg-desktop-portal/portal-docs.html#gdbus-org.freedesktop.portal.Wallpaper). 187 | 188 | [pipewire]: https://pipewire.org 189 | -------------------------------------------------------------------------------- /doc/libportal.svg: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 30 | 32 | 33 | -------------------------------------------------------------------------------- /doc/libportal.toml.in: -------------------------------------------------------------------------------- 1 | [library] 2 | version = "@VERSION@" 3 | description = "Flatpak portal library" 4 | authors = "Flatpak" 5 | license = "LGPL-3.0-only" 6 | browse_url = "https://github.com/flatpak/libportal" 7 | repository_url = "https://github.com/flatpak/libportal.git" 8 | website_url = "https://libportal.org/" 9 | docs_url = "https://libportal.org/" 10 | logo_url = "libportal.svg" 11 | dependencies = [ 12 | "GObject-2.0", 13 | "Gtk-4.0", 14 | ] 15 | devhelp = true 16 | search_index = true 17 | 18 | [dependencies."GObject-2.0"] 19 | name = "GObject" 20 | description = "The base type system library" 21 | docs_url = "https://developer.gnome.org/gobject/stable" 22 | 23 | [dependencies."Gtk-4.0"] 24 | name = "GTK" 25 | description = "The GTK toolkit" 26 | docs_url = "https://docs.gtk.org/gtk4/" 27 | 28 | [theme] 29 | name = "basic" 30 | show_index_summary = true 31 | show_class_hierarchy = true 32 | 33 | [source-location] 34 | # The base URL for the web UI 35 | base_url = "https://github.com/flatpak/libportal/blob/main/" 36 | 37 | [extra] 38 | urlmap_file = "urlmap.js" 39 | content_files = [ 40 | "libportal.md", 41 | ] 42 | content_images = [ 43 | "libportal.svg", 44 | "favicon-32x32.png", 45 | "favicon-128x128.png", 46 | "favicon-180x180.png", 47 | "favicon-192x192.png", 48 | ] 49 | -------------------------------------------------------------------------------- /doc/meson.build: -------------------------------------------------------------------------------- 1 | toml_data = configuration_data() 2 | toml_data.set('VERSION', meson.project_version()) 3 | 4 | libportal_toml = configure_file( 5 | input: 'libportal.toml.in', 6 | output: 'libportal.toml', 7 | configuration: toml_data 8 | ) 9 | 10 | dependency('gi-docgen', version: '>= 2021.1', 11 | fallback: ['gi-docgen', 'dummy_dep'], 12 | native: true, 13 | required: get_option('docs')) 14 | 15 | gidocgen = find_program('gi-docgen') 16 | 17 | docs_dir = get_option('datadir') / 'doc' 18 | 19 | gidocgen_opts = [ 20 | '--quiet', 21 | '--add-include-path=@0@'.format(meson.current_build_dir() / '../../libportal'), 22 | '--no-namespace-dir', 23 | '--content-dir=@0@'.format(meson.current_source_dir()), 24 | ] 25 | if get_option('werror') 26 | gidocgen_opts += ['--fatal-warnings'] 27 | endif 28 | 29 | custom_target('libportal-doc', 30 | input: [ libportal_toml, libportal_gir[0] ], 31 | output: 'libportal-1', 32 | command: [ 33 | gidocgen, 34 | 'generate', 35 | gidocgen_opts, 36 | '--config=@INPUT0@', 37 | '--output-dir=@OUTPUT@', 38 | '@INPUT1@', 39 | ], 40 | build_by_default: true, 41 | install: true, 42 | install_dir: docs_dir, 43 | ) 44 | -------------------------------------------------------------------------------- /doc/release-checklist.md: -------------------------------------------------------------------------------- 1 | libportal release checklist 2 | =========================== 3 | 4 | * Update NEWS 5 | * Check that version number in `meson.build` is correct 6 | * Update release date in `NEWS` 7 | * Commit the changes 8 | * `meson dist -C ${builddir}` 9 | * Do any final smoke-testing, e.g. update a package, install and test it 10 | * `git evtag sign $VERSION` 11 | * `git push --atomic origin main $VERSION` 12 | * https://github.com/flatpak/libportal/releases/new 13 | * Fill in the new version's tag in the "Tag version" box 14 | * Title: `$VERSION` 15 | * Copy the `NEWS` text into the description 16 | * Upload the tarball that you built with `meson dist` 17 | * Get the `sha256sum` of the tarball and append it to the description 18 | * `Publish release` 19 | 20 | After the release: 21 | 22 | * Update version number in `meson.build` to the next release version 23 | * Start a new section in `NEWS` 24 | -------------------------------------------------------------------------------- /doc/urlmap.js: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 GNOME Foundation 2 | // SPDX-License-Identifier: LGPL-2.1-or-later 3 | 4 | // Copied from GTK 5 | 6 | // A map between namespaces and base URLs for their online documentation 7 | baseURLs = [ 8 | ["GLib", "https://docs.gtk.org/glib/"], 9 | ["Gio", "https://docs.gtk.org/gio/"], 10 | ["GObject", "https://docs.gtk.org/gobject/"], 11 | ["Gdk", "https://docs.gtk.org/gdk4/"], 12 | ["Gsk", "https://docs.gtk.org/gsk4/"], 13 | ["Gtk", "https://docs.gtk.org/gtk4/"], 14 | ["Pango", "https://docs.gtk.org/Pango/"] 15 | ]; 16 | -------------------------------------------------------------------------------- /libportal/TODO: -------------------------------------------------------------------------------- 1 | portal version checks ? 2 | thread-safety ? 3 | -------------------------------------------------------------------------------- /libportal/account.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef enum { 27 | XDP_USER_INFORMATION_FLAG_NONE = 0 28 | } XdpUserInformationFlags; 29 | 30 | XDP_PUBLIC 31 | void xdp_portal_get_user_information (XdpPortal *portal, 32 | XdpParent *parent, 33 | const char *reason, 34 | XdpUserInformationFlags flags, 35 | GCancellable *cancellable, 36 | GAsyncReadyCallback callback, 37 | gpointer data); 38 | 39 | XDP_PUBLIC 40 | GVariant * xdp_portal_get_user_information_finish (XdpPortal *portal, 41 | GAsyncResult *result, 42 | GError **error); 43 | 44 | G_END_DECLS 45 | -------------------------------------------------------------------------------- /libportal/background.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpBackgroundFlags: 28 | * @XDP_BACKGROUND_FLAG_NONE: No options 29 | * @XDP_BACKGROUND_FLAG_AUTOSTART: Request autostart as well 30 | * @XDP_BACKGROUND_FLAG_ACTIVATABLE: Whether the application is D-Bus-activatable 31 | * 32 | * Options to use when requesting background. 33 | */ 34 | typedef enum { 35 | XDP_BACKGROUND_FLAG_NONE = 0, 36 | XDP_BACKGROUND_FLAG_AUTOSTART = 1 << 0, 37 | XDP_BACKGROUND_FLAG_ACTIVATABLE = 1 << 1 38 | } XdpBackgroundFlags; 39 | 40 | XDP_PUBLIC 41 | void xdp_portal_request_background (XdpPortal *portal, 42 | XdpParent *parent, 43 | char *reason, 44 | GPtrArray *commandline, 45 | XdpBackgroundFlags flags, 46 | GCancellable *cancellable, 47 | GAsyncReadyCallback callback, 48 | gpointer user_data); 49 | 50 | XDP_PUBLIC 51 | gboolean xdp_portal_request_background_finish (XdpPortal *portal, 52 | GAsyncResult *result, 53 | GError **error); 54 | 55 | XDP_PUBLIC 56 | void xdp_portal_set_background_status (XdpPortal *portal, 57 | const char *status_message, 58 | GCancellable *cancellable, 59 | GAsyncReadyCallback callback, 60 | gpointer data); 61 | 62 | XDP_PUBLIC 63 | gboolean xdp_portal_set_background_status_finish (XdpPortal *portal, 64 | GAsyncResult *result, 65 | GError **error); 66 | 67 | G_END_DECLS 68 | -------------------------------------------------------------------------------- /libportal/camera.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | XDP_PUBLIC 27 | gboolean xdp_portal_is_camera_present (XdpPortal *portal); 28 | 29 | typedef enum { 30 | XDP_CAMERA_FLAG_NONE = 0 31 | } XdpCameraFlags; 32 | 33 | XDP_PUBLIC 34 | void xdp_portal_access_camera (XdpPortal *portal, 35 | XdpParent *parent, 36 | XdpCameraFlags flags, 37 | GCancellable *cancellable, 38 | GAsyncReadyCallback callback, 39 | gpointer data); 40 | 41 | XDP_PUBLIC 42 | gboolean xdp_portal_access_camera_finish (XdpPortal *portal, 43 | GAsyncResult *result, 44 | GError **error); 45 | 46 | XDP_PUBLIC 47 | int xdp_portal_open_pipewire_remote_for_camera (XdpPortal *portal); 48 | 49 | G_END_DECLS 50 | -------------------------------------------------------------------------------- /libportal/dynamic-launcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Matthew Leeds 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpLauncherType: 28 | * @XDP_LAUNCHER_APPLICATION: a launcher for a regular application 29 | * @XDP_LAUNCHER_WEBAPP: a launcher for a web app 30 | * 31 | * The type of a launcher. 32 | */ 33 | typedef enum { 34 | XDP_LAUNCHER_APPLICATION = 1 << 0, 35 | XDP_LAUNCHER_WEBAPP = 1 << 1 36 | } XdpLauncherType; 37 | 38 | XDP_PUBLIC 39 | void xdp_portal_dynamic_launcher_prepare_install (XdpPortal *portal, 40 | XdpParent *parent, 41 | const char *name, 42 | GVariant *icon_v, 43 | XdpLauncherType launcher_type, 44 | const char *target, 45 | gboolean editable_name, 46 | gboolean editable_icon, 47 | GCancellable *cancellable, 48 | GAsyncReadyCallback callback, 49 | gpointer data); 50 | 51 | XDP_PUBLIC 52 | GVariant *xdp_portal_dynamic_launcher_prepare_install_finish (XdpPortal *portal, 53 | GAsyncResult *result, 54 | GError **error); 55 | 56 | XDP_PUBLIC 57 | char *xdp_portal_dynamic_launcher_request_install_token (XdpPortal *portal, 58 | const char *name, 59 | GVariant *icon_v, 60 | GError **error); 61 | 62 | XDP_PUBLIC 63 | gboolean xdp_portal_dynamic_launcher_install (XdpPortal *portal, 64 | const char *token, 65 | const char *desktop_file_id, 66 | const char *desktop_entry, 67 | GError **error); 68 | 69 | XDP_PUBLIC 70 | gboolean xdp_portal_dynamic_launcher_uninstall (XdpPortal *portal, 71 | const char *desktop_file_id, 72 | GError **error); 73 | 74 | XDP_PUBLIC 75 | char *xdp_portal_dynamic_launcher_get_desktop_entry (XdpPortal *portal, 76 | const char *desktop_file_id, 77 | GError **error); 78 | 79 | XDP_PUBLIC 80 | GVariant *xdp_portal_dynamic_launcher_get_icon (XdpPortal *portal, 81 | const char *desktop_file_id, 82 | char **out_icon_format, 83 | guint *out_icon_size, 84 | GError **error); 85 | 86 | XDP_PUBLIC 87 | gboolean xdp_portal_dynamic_launcher_launch (XdpPortal *portal, 88 | const char *desktop_file_id, 89 | const char *activation_token, 90 | GError **error); 91 | 92 | G_END_DECLS 93 | -------------------------------------------------------------------------------- /libportal/email.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef enum { 27 | XDP_EMAIL_FLAG_NONE = 0 28 | } XdpEmailFlags; 29 | 30 | XDP_PUBLIC 31 | void xdp_portal_compose_email (XdpPortal *portal, 32 | XdpParent *parent, 33 | const char *const *addresses, 34 | const char *const *cc, 35 | const char *const *bcc, 36 | const char *subject, 37 | const char *body, 38 | const char *const *attachments, 39 | XdpEmailFlags flags, 40 | GCancellable *cancellable, 41 | GAsyncReadyCallback callback, 42 | gpointer data); 43 | 44 | XDP_PUBLIC 45 | gboolean xdp_portal_compose_email_finish (XdpPortal *portal, 46 | GAsyncResult *result, 47 | GError **error); 48 | 49 | G_END_DECLS 50 | -------------------------------------------------------------------------------- /libportal/filechooser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpOpenFileFlags: 28 | * @XDP_OPEN_FILE_FLAG_NONE: No options 29 | * @XDP_OPEN_FILE_FLAG_MULTIPLE: Allow selecting multiple files 30 | * 31 | * Options for opening files. 32 | */ 33 | typedef enum { 34 | XDP_OPEN_FILE_FLAG_NONE = 0, 35 | XDP_OPEN_FILE_FLAG_MULTIPLE = 1 << 0, 36 | } XdpOpenFileFlags; 37 | 38 | XDP_PUBLIC 39 | void xdp_portal_open_file (XdpPortal *portal, 40 | XdpParent *parent, 41 | const char *title, 42 | GVariant *filters, 43 | GVariant *current_filter, 44 | GVariant *choices, 45 | XdpOpenFileFlags flags, 46 | GCancellable *cancellable, 47 | GAsyncReadyCallback callback, 48 | gpointer data); 49 | 50 | XDP_PUBLIC 51 | GVariant *xdp_portal_open_file_finish (XdpPortal *portal, 52 | GAsyncResult *result, 53 | GError **error); 54 | 55 | typedef enum { 56 | XDP_SAVE_FILE_FLAG_NONE = 0 57 | } XdpSaveFileFlags; 58 | 59 | XDP_PUBLIC 60 | void xdp_portal_save_file (XdpPortal *portal, 61 | XdpParent *parent, 62 | const char *title, 63 | const char *current_name, 64 | const char *current_folder, 65 | const char *current_file, 66 | GVariant *filters, 67 | GVariant *current_filter, 68 | GVariant *choices, 69 | XdpSaveFileFlags flags, 70 | GCancellable *cancellable, 71 | GAsyncReadyCallback callback, 72 | gpointer data); 73 | 74 | XDP_PUBLIC 75 | GVariant *xdp_portal_save_file_finish (XdpPortal *portal, 76 | GAsyncResult *result, 77 | GError **error); 78 | 79 | XDP_PUBLIC 80 | void xdp_portal_save_files (XdpPortal *portal, 81 | XdpParent *parent, 82 | const char *title, 83 | const char *current_name, 84 | const char *current_folder, 85 | GVariant *files, 86 | GVariant *choices, 87 | XdpSaveFileFlags flags, 88 | GCancellable *cancellable, 89 | GAsyncReadyCallback callback, 90 | gpointer data); 91 | 92 | XDP_PUBLIC 93 | GVariant *xdp_portal_save_files_finish (XdpPortal *portal, 94 | GAsyncResult *result, 95 | GError **error); 96 | 97 | G_END_DECLS 98 | -------------------------------------------------------------------------------- /libportal/glib-backports.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright © 2024 GNOME Foundation Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include 25 | 26 | #if !GLIB_CHECK_VERSION(2, 76, 0) 27 | 28 | static inline gboolean 29 | g_clear_fd (int *fd_ptr, 30 | GError **error) 31 | { 32 | int fd = *fd_ptr; 33 | 34 | *fd_ptr = -1; 35 | 36 | if (fd < 0) 37 | return TRUE; 38 | 39 | /* Suppress "Not available before" warning */ 40 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS 41 | return g_close (fd, error); 42 | G_GNUC_END_IGNORE_DEPRECATIONS 43 | } 44 | 45 | static inline void 46 | _g_clear_fd_ignore_error (int *fd_ptr) 47 | { 48 | /* Don't overwrite thread-local errno if closing the fd fails */ 49 | int errsv = errno; 50 | 51 | /* Suppress "Not available before" warning */ 52 | G_GNUC_BEGIN_IGNORE_DEPRECATIONS 53 | 54 | if (!g_clear_fd (fd_ptr, NULL)) 55 | { 56 | /* Do nothing: we ignore all errors, except for EBADF which 57 | * is a programming error, checked for by g_close(). */ 58 | } 59 | 60 | G_GNUC_END_IGNORE_DEPRECATIONS 61 | 62 | errno = errsv; 63 | } 64 | 65 | #define g_autofd __attribute__((cleanup(_g_clear_fd_ignore_error))) 66 | 67 | #endif 68 | 69 | #if !GLIB_CHECK_VERSION(2, 84, 0) 70 | static inline unsigned int 71 | backport_steal_handle_id (unsigned int *handle_pointer) 72 | { 73 | unsigned int handle; 74 | 75 | handle = *handle_pointer; 76 | *handle_pointer = 0; 77 | 78 | return handle; 79 | } 80 | #define g_steal_handle_id(hp) backport_steal_handle_id (hp) 81 | #endif 82 | -------------------------------------------------------------------------------- /libportal/inhibit.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpInhibitFlags: 28 | * @XDP_INHIBIT_FLAG_LOGOUT: Inhibit logout 29 | * @XDP_INHIBIT_FLAG_USER_SWITCH: Inhibit user switching 30 | * @XDP_INHIBIT_FLAG_SUSPEND: Inhibit suspend 31 | * @XDP_INHIBIT_FLAG_IDLE: Inhibit the session going idle 32 | * 33 | * Flags that determine what session status changes are inhibited. 34 | */ 35 | typedef enum { 36 | XDP_INHIBIT_FLAG_LOGOUT = 1 << 0, 37 | XDP_INHIBIT_FLAG_USER_SWITCH = 1 << 1, 38 | XDP_INHIBIT_FLAG_SUSPEND = 1 << 2, 39 | XDP_INHIBIT_FLAG_IDLE = 1 << 3 40 | } XdpInhibitFlags; 41 | 42 | XDP_PUBLIC 43 | void xdp_portal_session_inhibit (XdpPortal *portal, 44 | XdpParent *parent, 45 | const char *reason, 46 | XdpInhibitFlags flags, 47 | GCancellable *cancellable, 48 | GAsyncReadyCallback callback, 49 | gpointer data); 50 | 51 | XDP_PUBLIC 52 | int xdp_portal_session_inhibit_finish (XdpPortal *portal, 53 | GAsyncResult *result, 54 | GError **error); 55 | 56 | XDP_PUBLIC 57 | void xdp_portal_session_uninhibit (XdpPortal *portal, 58 | int id); 59 | 60 | /** 61 | * XdpLoginSessionState: 62 | * @XDP_LOGIN_SESSION_RUNNING: the session is running 63 | * @XDP_LOGIN_SESSION_QUERY_END: the session is in the query end phase, 64 | * during which applications can save their state or inhibit the 65 | * session from ending 66 | * @XDP_LOGIN_SESSION_ENDING: the session is about to end 67 | * 68 | * The values of this enum are returned in the [signal@Portal::session-state-changed] signal 69 | * to indicate the current state of the user session. 70 | */ 71 | typedef enum { 72 | XDP_LOGIN_SESSION_RUNNING = 1, 73 | XDP_LOGIN_SESSION_QUERY_END = 2, 74 | XDP_LOGIN_SESSION_ENDING = 3, 75 | } XdpLoginSessionState; 76 | 77 | typedef enum { 78 | XDP_SESSION_MONITOR_FLAG_NONE = 0 79 | } XdpSessionMonitorFlags; 80 | 81 | XDP_PUBLIC 82 | void xdp_portal_session_monitor_start (XdpPortal *portal, 83 | XdpParent *parent, 84 | XdpSessionMonitorFlags flags, 85 | GCancellable *cancellable, 86 | GAsyncReadyCallback callback, 87 | gpointer data); 88 | 89 | XDP_PUBLIC 90 | gboolean xdp_portal_session_monitor_start_finish (XdpPortal *portal, 91 | GAsyncResult *result, 92 | GError **error); 93 | 94 | XDP_PUBLIC 95 | void xdp_portal_session_monitor_stop (XdpPortal *portal); 96 | 97 | XDP_PUBLIC 98 | void xdp_portal_session_monitor_query_end_response (XdpPortal *portal); 99 | 100 | G_END_DECLS 101 | -------------------------------------------------------------------------------- /libportal/inputcapture-pointerbarrier.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Red Hat, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | #define XDP_TYPE_INPUT_CAPTURE_POINTER_BARRIER (xdp_input_capture_pointer_barrier_get_type ()) 27 | 28 | XDP_PUBLIC 29 | G_DECLARE_FINAL_TYPE (XdpInputCapturePointerBarrier, xdp_input_capture_pointer_barrier, XDP, INPUT_CAPTURE_POINTER_BARRIER, GObject) 30 | 31 | G_END_DECLS 32 | -------------------------------------------------------------------------------- /libportal/inputcapture-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Red Hat, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "inputcapture-pointerbarrier.h" 23 | #include "inputcapture-zone.h" 24 | 25 | guint 26 | _xdp_input_capture_pointer_barrier_get_id (XdpInputCapturePointerBarrier *barrier); 27 | 28 | void 29 | _xdp_input_capture_pointer_barrier_set_is_active (XdpInputCapturePointerBarrier *barrier, gboolean active); 30 | 31 | void 32 | _xdp_input_capture_zone_invalidate_and_free (XdpInputCaptureZone *zone); 33 | -------------------------------------------------------------------------------- /libportal/inputcapture-zone.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Red Hat, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include "inputcapture-zone.h" 23 | 24 | /** 25 | * XdpInputCaptureZone 26 | * 27 | * A representation of a zone that supports input capture. 28 | * 29 | * The [class@XdpInputCaptureZone] object is used to represent a zone on the 30 | * user-visible desktop that may be used to set up 31 | * [class@XdpInputCapturePointerBarrier] objects. In most cases, the set of 32 | * [class@XdpInputCaptureZone] objects represent the available monitors but the 33 | * exact implementation is up to the implementation. 34 | */ 35 | 36 | enum 37 | { 38 | PROP_0, 39 | 40 | PROP_WIDTH, 41 | PROP_HEIGHT, 42 | PROP_X, 43 | PROP_Y, 44 | PROP_ZONE_SET, 45 | PROP_IS_VALID, 46 | 47 | N_PROPERTIES 48 | }; 49 | 50 | static GParamSpec *zone_properties[N_PROPERTIES] = { NULL, }; 51 | 52 | struct _XdpInputCaptureZone { 53 | GObject parent_instance; 54 | 55 | unsigned int width; 56 | unsigned int height; 57 | int x; 58 | int y; 59 | 60 | unsigned int zone_set; 61 | 62 | gboolean is_valid; 63 | }; 64 | 65 | G_DEFINE_TYPE (XdpInputCaptureZone, xdp_input_capture_zone, G_TYPE_OBJECT) 66 | 67 | static void 68 | xdp_input_capture_zone_get_property (GObject *object, 69 | unsigned int property_id, 70 | GValue *value, 71 | GParamSpec *pspec) 72 | { 73 | 74 | XdpInputCaptureZone *zone = XDP_INPUT_CAPTURE_ZONE (object); 75 | 76 | switch (property_id) 77 | { 78 | case PROP_WIDTH: 79 | g_value_set_uint (value, zone->width); 80 | break; 81 | case PROP_HEIGHT: 82 | g_value_set_uint (value, zone->height); 83 | break; 84 | case PROP_X: 85 | g_value_set_int (value, zone->x); 86 | break; 87 | case PROP_Y: 88 | g_value_set_int (value, zone->y); 89 | break; 90 | case PROP_ZONE_SET: 91 | g_value_set_uint (value, zone->zone_set); 92 | break; 93 | case PROP_IS_VALID: 94 | g_value_set_boolean (value, zone->is_valid); 95 | break; 96 | default: 97 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 98 | break; 99 | } 100 | } 101 | 102 | static void 103 | xdp_input_capture_zone_set_property (GObject *object, 104 | unsigned int property_id, 105 | const GValue *value, 106 | GParamSpec *pspec) 107 | { 108 | XdpInputCaptureZone *zone = XDP_INPUT_CAPTURE_ZONE (object); 109 | 110 | switch (property_id) 111 | { 112 | case PROP_WIDTH: 113 | zone->width = g_value_get_uint (value); 114 | break; 115 | case PROP_HEIGHT: 116 | zone->height = g_value_get_uint (value); 117 | break; 118 | case PROP_X: 119 | zone->x = g_value_get_int (value); 120 | break; 121 | case PROP_Y: 122 | zone->y = g_value_get_int (value); 123 | break; 124 | case PROP_ZONE_SET: 125 | zone->zone_set = g_value_get_uint (value); 126 | break; 127 | case PROP_IS_VALID: 128 | zone->is_valid = g_value_get_boolean (value); 129 | break; 130 | default: 131 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 132 | break; 133 | } 134 | } 135 | 136 | static void 137 | xdp_input_capture_zone_class_init (XdpInputCaptureZoneClass *klass) 138 | { 139 | GObjectClass *object_class = G_OBJECT_CLASS (klass); 140 | 141 | object_class->get_property = xdp_input_capture_zone_get_property; 142 | object_class->set_property = xdp_input_capture_zone_set_property; 143 | 144 | /** 145 | * XdpInputCaptureZone:width: 146 | * 147 | * The width of this zone in logical pixels 148 | */ 149 | zone_properties[PROP_WIDTH] = 150 | g_param_spec_uint ("width", 151 | "zone width", 152 | "The zone width in logical pixels", 153 | 0, UINT_MAX, 0, 154 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); 155 | 156 | /** 157 | * XdpInputCaptureZone:height: 158 | * 159 | * The height of this zone in logical pixels 160 | */ 161 | zone_properties[PROP_HEIGHT] = 162 | g_param_spec_uint ("height", 163 | "zone height", 164 | "The zone height in logical pixels", 165 | 0, UINT_MAX, 0, 166 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); 167 | 168 | /** 169 | * XdpInputCaptureZone:x: 170 | * 171 | * The x offset of this zone in logical pixels 172 | */ 173 | zone_properties[PROP_X] = 174 | g_param_spec_int ("x", 175 | "zone x offset", 176 | "The zone x offset in logical pixels", 177 | INT_MIN, INT_MAX, 0, 178 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); 179 | /** 180 | * XdpInputCaptureZone:y: 181 | * 182 | * The x offset of this zone in logical pixels 183 | */ 184 | zone_properties[PROP_Y] = 185 | g_param_spec_int ("y", 186 | "zone y offset", 187 | "The zone y offset in logical pixels", 188 | INT_MIN, INT_MAX, 0, 189 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); 190 | 191 | /** 192 | * XdpInputCaptureZone:zone_set: 193 | * 194 | * The unique zone_set number assigned to this set of zones. A set of zones as 195 | * returned by [method@InputCaptureSession.get_zones] have the same zone_set 196 | * number and only one set of zones may be valid at any time (the most 197 | * recently returned set). 198 | */ 199 | zone_properties[PROP_ZONE_SET] = 200 | g_param_spec_uint ("zone_set", 201 | "zone set number", 202 | "The zone_set number when this zone was retrieved", 203 | 0, UINT_MAX, 0, 204 | G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); 205 | 206 | /** 207 | * XdpInputCaptureZone:is-valid: 208 | * 209 | * A boolean indicating whether this zone is currently valid. Zones are 210 | * invalidated by the Portal's ZonesChanged signal, see 211 | * [signal@InputCaptureSession::zones-changed]. 212 | * 213 | * Once invalidated, a Zone can be discarded by the caller, it cannot become 214 | * valid again. 215 | */ 216 | zone_properties[PROP_IS_VALID] = 217 | g_param_spec_boolean ("is-valid", 218 | "validity check", 219 | "True if this zone is currently valid", 220 | TRUE, 221 | G_PARAM_READWRITE); 222 | 223 | g_object_class_install_properties (object_class, 224 | N_PROPERTIES, 225 | zone_properties); 226 | } 227 | 228 | static void 229 | xdp_input_capture_zone_init (XdpInputCaptureZone *zone) 230 | { 231 | } 232 | 233 | void 234 | _xdp_input_capture_zone_invalidate_and_free (XdpInputCaptureZone *zone) 235 | { 236 | g_object_set (zone, "is-valid", FALSE, NULL); 237 | g_object_unref (zone); 238 | } 239 | -------------------------------------------------------------------------------- /libportal/inputcapture-zone.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Red Hat, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | #define XDP_TYPE_INPUT_CAPTURE_ZONE (xdp_input_capture_zone_get_type ()) 27 | 28 | XDP_PUBLIC 29 | G_DECLARE_FINAL_TYPE (XdpInputCaptureZone, xdp_input_capture_zone, XDP, INPUT_CAPTURE_ZONE, GObject) 30 | 31 | G_END_DECLS 32 | -------------------------------------------------------------------------------- /libportal/inputcapture.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | G_BEGIN_DECLS 29 | 30 | #define XDP_TYPE_INPUT_CAPTURE_SESSION (xdp_input_capture_session_get_type ()) 31 | 32 | XDP_PUBLIC 33 | G_DECLARE_FINAL_TYPE (XdpInputCaptureSession, xdp_input_capture_session, XDP, INPUT_CAPTURE_SESSION, GObject) 34 | 35 | /** 36 | * XdpInputCapability: 37 | * @XDP_INPUT_CAPABILITY_NONE: no device 38 | * @XDP_INPUT_CAPABILITY_KEYBOARD: capture the keyboard 39 | * @XDP_INPUT_CAPABILITY_POINTER: capture pointer events 40 | * @XDP_INPUT_CAPABILITY_TOUCHSCREEN: capture touchscreen events 41 | * 42 | * Flags to specify what input device capabilities should be captured 43 | */ 44 | typedef enum { 45 | XDP_INPUT_CAPABILITY_NONE = 0, 46 | XDP_INPUT_CAPABILITY_KEYBOARD = 1 << 0, 47 | XDP_INPUT_CAPABILITY_POINTER = 1 << 1, 48 | XDP_INPUT_CAPABILITY_TOUCHSCREEN = 1 << 2 49 | } XdpInputCapability; 50 | 51 | 52 | XDP_PUBLIC 53 | void xdp_portal_create_input_capture_session (XdpPortal *portal, 54 | XdpParent *parent, 55 | XdpInputCapability capabilities, 56 | GCancellable *cancellable, 57 | GAsyncReadyCallback callback, 58 | gpointer data); 59 | 60 | XDP_PUBLIC 61 | XdpInputCaptureSession * xdp_portal_create_input_capture_session_finish (XdpPortal *portal, 62 | GAsyncResult *result, 63 | GError **error); 64 | 65 | XDP_PUBLIC 66 | XdpSession *xdp_input_capture_session_get_session (XdpInputCaptureSession *session); 67 | 68 | XDP_PUBLIC 69 | GList * xdp_input_capture_session_get_zones (XdpInputCaptureSession *session); 70 | 71 | XDP_PUBLIC 72 | void xdp_input_capture_session_set_pointer_barriers (XdpInputCaptureSession *session, 73 | GList *barriers, 74 | GCancellable *cancellable, 75 | GAsyncReadyCallback callback, 76 | gpointer data); 77 | 78 | XDP_PUBLIC 79 | GList * xdp_input_capture_session_set_pointer_barriers_finish (XdpInputCaptureSession *session, 80 | GAsyncResult *result, 81 | GError **error); 82 | 83 | XDP_PUBLIC 84 | void xdp_input_capture_session_enable (XdpInputCaptureSession *session); 85 | 86 | XDP_PUBLIC 87 | void xdp_input_capture_session_disable (XdpInputCaptureSession *session); 88 | 89 | XDP_PUBLIC 90 | void xdp_input_capture_session_release_at (XdpInputCaptureSession *session, 91 | guint activation_id, 92 | gdouble cursor_x_position, 93 | gdouble cursor_y_position); 94 | 95 | XDP_PUBLIC 96 | void xdp_input_capture_session_release (XdpInputCaptureSession *session, 97 | guint activation_id); 98 | 99 | XDP_PUBLIC 100 | int xdp_input_capture_session_connect_to_eis (XdpInputCaptureSession *session, 101 | GError **error); 102 | 103 | G_END_DECLS 104 | -------------------------------------------------------------------------------- /libportal/location.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpLocationAccuracy: 28 | * @XDP_LOCATION_ACCURACY_NONE: No particular accuracy 29 | * @XDP_LOCATION_ACCURACY_COUNTRY: Country-level accuracy 30 | * @XDP_LOCATION_ACCURACY_CITY: City-level accuracy 31 | * @XDP_LOCATION_ACCURACY_NEIGHBORHOOD: Neighborhood-level accuracy 32 | * @XDP_LOCATION_ACCURACY_STREET: Street-level accuracy 33 | * @XDP_LOCATION_ACCURACY_EXACT: Maximum accuracy 34 | * 35 | * The values of this enum indicate the desired level 36 | * of accuracy for location information. 37 | */ 38 | typedef enum { 39 | XDP_LOCATION_ACCURACY_NONE, 40 | XDP_LOCATION_ACCURACY_COUNTRY, 41 | XDP_LOCATION_ACCURACY_CITY, 42 | XDP_LOCATION_ACCURACY_NEIGHBORHOOD, 43 | XDP_LOCATION_ACCURACY_STREET, 44 | XDP_LOCATION_ACCURACY_EXACT 45 | } XdpLocationAccuracy; 46 | 47 | typedef enum { 48 | XDP_LOCATION_MONITOR_FLAG_NONE = 0 49 | } XdpLocationMonitorFlags; 50 | 51 | XDP_PUBLIC 52 | void xdp_portal_location_monitor_start (XdpPortal *portal, 53 | XdpParent *parent, 54 | guint distance_threshold, 55 | guint time_threshold, 56 | XdpLocationAccuracy accuracy, 57 | XdpLocationMonitorFlags flags, 58 | GCancellable *cancellable, 59 | GAsyncReadyCallback callback, 60 | gpointer data); 61 | 62 | XDP_PUBLIC 63 | gboolean xdp_portal_location_monitor_start_finish (XdpPortal *portal, 64 | GAsyncResult *result, 65 | GError **error); 66 | 67 | XDP_PUBLIC 68 | void xdp_portal_location_monitor_stop (XdpPortal *portal); 69 | 70 | G_END_DECLS 71 | -------------------------------------------------------------------------------- /libportal/notification.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef enum { 27 | XDP_NOTIFICATION_FLAG_NONE = 0 28 | } XdpNotificationFlags; 29 | 30 | XDP_PUBLIC 31 | void xdp_portal_add_notification (XdpPortal *portal, 32 | const char *id, 33 | GVariant *notification, 34 | XdpNotificationFlags flags, 35 | GCancellable *cancellable, 36 | GAsyncReadyCallback callback, 37 | gpointer data); 38 | 39 | XDP_PUBLIC 40 | gboolean xdp_portal_add_notification_finish (XdpPortal *portal, 41 | GAsyncResult *result, 42 | GError **error); 43 | 44 | XDP_PUBLIC 45 | void xdp_portal_remove_notification (XdpPortal *portal, 46 | const char *id); 47 | 48 | XDP_PUBLIC 49 | GVariant *xdp_portal_get_supported_notification_options (XdpPortal *portal, 50 | GError **error); 51 | 52 | G_END_DECLS 53 | -------------------------------------------------------------------------------- /libportal/openuri.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpOpenUriFlags: 28 | * @XDP_OPEN_URI_FLAG_NONE: No options 29 | * @XDP_OPEN_URI_FLAG_ASK: Use an application chooser for the given uri 30 | * @XDP_OPEN_URI_FLAG_WRITABLE: Allow writing to file (if uri points to a local file that is exported in the document portal and app is sandboxed itself) 31 | * 32 | * Options for opening uris. 33 | */ 34 | typedef enum { 35 | XDP_OPEN_URI_FLAG_NONE = 0, 36 | XDP_OPEN_URI_FLAG_ASK = 1 << 0, 37 | XDP_OPEN_URI_FLAG_WRITABLE = 1 << 1 38 | } XdpOpenUriFlags; 39 | 40 | XDP_PUBLIC 41 | void xdp_portal_open_uri (XdpPortal *portal, 42 | XdpParent *parent, 43 | const char *uri, 44 | XdpOpenUriFlags flags, 45 | GCancellable *cancellable, 46 | GAsyncReadyCallback callback, 47 | gpointer data); 48 | 49 | XDP_PUBLIC 50 | gboolean xdp_portal_open_uri_finish (XdpPortal *portal, 51 | GAsyncResult *result, 52 | GError **error); 53 | 54 | XDP_PUBLIC 55 | void xdp_portal_open_directory (XdpPortal *portal, 56 | XdpParent *parent, 57 | const char *uri, 58 | XdpOpenUriFlags flags, 59 | GCancellable *cancellable, 60 | GAsyncReadyCallback callback, 61 | gpointer data); 62 | 63 | XDP_PUBLIC 64 | gboolean xdp_portal_open_directory_finish (XdpPortal *portal, 65 | GAsyncResult *result, 66 | GError **error); 67 | 68 | G_END_DECLS 69 | -------------------------------------------------------------------------------- /libportal/parent-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "parent.h" 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef void (* XdpParentExported) (XdpParent *parent, 27 | const char *handle, 28 | gpointer data); 29 | typedef gboolean (* XdpParentExport) (XdpParent *parent, 30 | XdpParentExported callback, 31 | gpointer data); 32 | typedef void (* XdpParentUnexport) (XdpParent *parent); 33 | 34 | struct _XdpParent { 35 | /*< private >*/ 36 | XdpParentExport parent_export; 37 | XdpParentUnexport parent_unexport; 38 | GObject *object; 39 | XdpParentExported callback; 40 | char *exported_handle; 41 | gpointer data; 42 | }; 43 | 44 | G_END_DECLS 45 | -------------------------------------------------------------------------------- /libportal/parent.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | #include "parent-private.h" 22 | 23 | 24 | /** 25 | * XdpParent 26 | * 27 | * Parent window abstraction. 28 | * 29 | * The [struct@Parent] struct provides an abstract way to represent a window, 30 | * without introducing a dependency on a toolkit library. 31 | * 32 | * XdpParent implementations for GTK 3, GTK 4, Qt 5, and Qt 6 are available as 33 | * separate libraries. 34 | */ 35 | G_DEFINE_BOXED_TYPE (XdpParent, xdp_parent, xdp_parent_copy, xdp_parent_free) 36 | 37 | /** 38 | * xdp_parent_copy: 39 | * @source: a [struct@Parent] 40 | * 41 | * Copies @source into a new [struct@Parent]. 42 | * 43 | * Returns: (transfer full): an [struct@Parent] that is a copy of @source 44 | */ 45 | XdpParent * 46 | xdp_parent_copy (XdpParent *source) 47 | { 48 | XdpParent *parent; 49 | 50 | parent = g_new0 (XdpParent, 1); 51 | 52 | parent->parent_export = source->parent_export; 53 | parent->parent_unexport = source->parent_unexport; 54 | g_set_object (&parent->object, source->object); 55 | parent->data = source->data; 56 | parent->exported_handle = g_strdup (source->exported_handle); 57 | 58 | return parent; 59 | } 60 | 61 | /** 62 | * xdp_parent_free: 63 | * @parent: an [struct@Parent] 64 | * 65 | * Frees @parent. 66 | */ 67 | void 68 | xdp_parent_free (XdpParent *parent) 69 | { 70 | g_clear_pointer (&parent->exported_handle, g_free); 71 | g_clear_object (&parent->object); 72 | g_free (parent); 73 | } 74 | -------------------------------------------------------------------------------- /libportal/parent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | #define XDP_TYPE_PARENT (xdp_parent_get_type ()) 27 | 28 | XDP_PUBLIC 29 | GType xdp_parent_get_type (void) G_GNUC_CONST; 30 | 31 | XDP_PUBLIC 32 | XdpParent *xdp_parent_copy (XdpParent *source); 33 | 34 | XDP_PUBLIC 35 | void xdp_parent_free (XdpParent *parent); 36 | 37 | G_DEFINE_AUTOPTR_CLEANUP_FUNC (XdpParent, xdp_parent_free) 38 | 39 | G_END_DECLS 40 | -------------------------------------------------------------------------------- /libportal/portal-enums.c.template: -------------------------------------------------------------------------------- 1 | /*** BEGIN file-header ***/ 2 | 3 | #include "config.h" 4 | 5 | #include 6 | 7 | /*** END file-header ***/ 8 | 9 | /*** BEGIN file-production ***/ 10 | /* enumerations from "@basename@" */ 11 | /*** END file-production ***/ 12 | 13 | /*** BEGIN value-header ***/ 14 | GType 15 | @enum_name@_get_type (void) 16 | { 17 | static gsize g_define_type_id__volatile = 0; 18 | 19 | if (g_once_init_enter (&g_define_type_id__volatile)) 20 | { 21 | static const G@Type@Value values[] = { 22 | /*** END value-header ***/ 23 | 24 | /*** BEGIN value-production ***/ 25 | { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, 26 | /*** END value-production ***/ 27 | 28 | /*** BEGIN value-tail ***/ 29 | { 0, NULL, NULL } 30 | }; 31 | GType g_define_type_id = 32 | g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); 33 | g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); 34 | } 35 | 36 | return g_define_type_id__volatile; 37 | } 38 | 39 | /*** END value-tail ***/ 40 | 41 | /*** BEGIN file-tail ***/ 42 | 43 | /*** END file-tail ***/ 44 | -------------------------------------------------------------------------------- /libportal/portal-enums.h.template: -------------------------------------------------------------------------------- 1 | /*** BEGIN file-header ***/ 2 | #pragma once 3 | 4 | #include 5 | #include 6 | 7 | G_BEGIN_DECLS 8 | /*** END file-header ***/ 9 | 10 | /*** BEGIN file-production ***/ 11 | 12 | /* enumerations from "@basename@" */ 13 | /*** END file-production ***/ 14 | 15 | /*** BEGIN value-header ***/ 16 | XDP_PUBLIC 17 | GType @enum_name@_get_type (void) G_GNUC_CONST; 18 | #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) 19 | /*** END value-header ***/ 20 | 21 | /*** BEGIN file-tail ***/ 22 | G_END_DECLS 23 | 24 | /*** END file-tail ***/ 25 | -------------------------------------------------------------------------------- /libportal/portal-gtk3.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | #include "portal-gtk3.h" 22 | 23 | #include "parent-private.h" 24 | 25 | #ifdef GDK_WINDOWING_X11 26 | #include 27 | #endif 28 | #ifdef GDK_WINDOWING_WAYLAND 29 | #include 30 | #endif 31 | 32 | static void 33 | _xdp_parent_exported_wayland (GdkWindow *window, 34 | const char *handle, 35 | gpointer data) 36 | 37 | { 38 | XdpParent *parent = data; 39 | g_autofree char *handle_str = g_strdup_printf ("wayland:%s", handle); 40 | 41 | g_assert (parent->exported_handle == NULL); 42 | 43 | parent->exported_handle = g_strdup (handle); 44 | parent->callback (parent, handle_str, parent->data); 45 | } 46 | 47 | static gboolean 48 | _xdp_parent_export_gtk (XdpParent *parent, 49 | XdpParentExported callback, 50 | gpointer data) 51 | { 52 | #ifdef GDK_WINDOWING_X11 53 | if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 54 | { 55 | GdkWindow *w = gtk_widget_get_window (GTK_WIDGET (parent->object)); 56 | guint32 xid = (guint32) gdk_x11_window_get_xid (w); 57 | g_autofree char *handle = g_strdup_printf ("x11:%x", xid); 58 | 59 | g_assert (parent->exported_handle == NULL); 60 | 61 | parent->exported_handle = g_strdup (handle); 62 | callback (parent, handle, data); 63 | return TRUE; 64 | } 65 | #endif 66 | #ifdef GDK_WINDOWING_WAYLAND 67 | if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 68 | { 69 | GdkWindow *w = gtk_widget_get_window (GTK_WIDGET (parent->object)); 70 | parent->callback = callback; 71 | parent->data = data; 72 | return gdk_wayland_window_export_handle (w, _xdp_parent_exported_wayland, parent, NULL); 73 | } 74 | #endif 75 | g_warning ("Couldn't export handle, unsupported windowing system"); 76 | return FALSE; 77 | } 78 | 79 | static void 80 | _xdp_parent_unexport_gtk (XdpParent *parent) 81 | { 82 | #ifdef GDK_WINDOWING_WAYLAND 83 | if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 84 | { 85 | GdkWindow *w = gtk_widget_get_window (GTK_WIDGET (parent->object)); 86 | gdk_wayland_window_unexport_handle (w); 87 | } 88 | #endif 89 | } 90 | 91 | /** 92 | * xdp_parent_new_gtk: 93 | * @window: a [class@Gtk.Window] 94 | * 95 | * Creates a new [struct@Parent] from @window. 96 | * 97 | * Returns: (transfer full): a [struct@Parent] 98 | */ 99 | XdpParent * 100 | xdp_parent_new_gtk (GtkWindow *window) 101 | { 102 | XdpParent *parent = g_new0 (XdpParent, 1); 103 | parent->parent_export = _xdp_parent_export_gtk; 104 | parent->parent_unexport = _xdp_parent_unexport_gtk; 105 | parent->object = (GObject *) g_object_ref (window); 106 | return parent; 107 | } 108 | -------------------------------------------------------------------------------- /libportal/portal-gtk3.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #if GTK_CHECK_VERSION(3,96,0) || GTK_CHECK_VERSION(4,0,0) 26 | #error "To use libportal with GTK4, include portal-gtk4.h" 27 | #endif 28 | 29 | G_BEGIN_DECLS 30 | 31 | XDP_PUBLIC 32 | XdpParent *xdp_parent_new_gtk (GtkWindow *window); 33 | 34 | G_END_DECLS 35 | -------------------------------------------------------------------------------- /libportal/portal-gtk4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | #include "portal-gtk4.h" 22 | 23 | #include "parent-private.h" 24 | 25 | #ifdef GDK_WINDOWING_X11 26 | #include 27 | #endif 28 | #ifdef GDK_WINDOWING_WAYLAND 29 | #include 30 | #endif 31 | 32 | static void 33 | _xdp_parent_exported_wayland (GdkToplevel *toplevel, 34 | const char *handle, 35 | gpointer data) 36 | 37 | { 38 | XdpParent *parent = data; 39 | g_autofree char *handle_str = g_strdup_printf ("wayland:%s", handle); 40 | 41 | g_assert (parent->exported_handle == NULL); 42 | 43 | parent->exported_handle = g_strdup (handle); 44 | parent->callback (parent, handle_str, parent->data); 45 | } 46 | 47 | static gboolean 48 | _xdp_parent_export_gtk (XdpParent *parent, 49 | XdpParentExported callback, 50 | gpointer data) 51 | { 52 | #ifdef GDK_WINDOWING_X11 53 | if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 54 | { 55 | GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (parent->object)); 56 | guint32 xid = (guint32) gdk_x11_surface_get_xid (surface); 57 | g_autofree char *handle = g_strdup_printf ("x11:%x", xid); 58 | 59 | g_assert (parent->exported_handle == NULL); 60 | 61 | parent->exported_handle = g_strdup (handle); 62 | callback (parent, handle, data); 63 | return TRUE; 64 | } 65 | #endif 66 | #ifdef GDK_WINDOWING_WAYLAND 67 | if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 68 | { 69 | GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (parent->object)); 70 | parent->callback = callback; 71 | parent->data = data; 72 | return gdk_wayland_toplevel_export_handle (GDK_TOPLEVEL (surface), 73 | _xdp_parent_exported_wayland, 74 | parent, 75 | NULL); 76 | } 77 | #endif 78 | g_warning ("Couldn't export handle, unsupported windowing system"); 79 | return FALSE; 80 | } 81 | 82 | static void 83 | _xdp_parent_unexport_gtk (XdpParent *parent) 84 | { 85 | #ifdef GDK_WINDOWING_WAYLAND 86 | if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (parent->object)))) 87 | { 88 | GdkSurface *surface = gtk_native_get_surface (GTK_NATIVE (parent->object)); 89 | 90 | #if GTK_CHECK_VERSION(4, 12, 0) 91 | gdk_wayland_toplevel_drop_exported_handle (GDK_TOPLEVEL (surface), parent->exported_handle); 92 | #else 93 | gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (surface)); 94 | #endif 95 | } 96 | #endif 97 | } 98 | 99 | /** 100 | * xdp_parent_new_gtk: 101 | * @window: a [class@Gtk.Window] 102 | * 103 | * Creates a new [struct@Parent] from @window. 104 | * 105 | * Returns: (transfer full): a [struct@Parent] 106 | */ 107 | XdpParent * 108 | xdp_parent_new_gtk (GtkWindow *window) 109 | { 110 | XdpParent *parent = g_new0 (XdpParent, 1); 111 | parent->parent_export = _xdp_parent_export_gtk; 112 | parent->parent_unexport = _xdp_parent_unexport_gtk; 113 | parent->object = (GObject *) g_object_ref (window); 114 | return parent; 115 | } 116 | -------------------------------------------------------------------------------- /libportal/portal-gtk4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | #if !(GTK_CHECK_VERSION(3,96,0) || GTK_CHECK_VERSION(4,0,0)) 26 | #error "To use libportal with GTK3, include portal-gtk3.h" 27 | #endif 28 | 29 | G_BEGIN_DECLS 30 | 31 | XDP_PUBLIC 32 | XdpParent *xdp_parent_new_gtk (GtkWindow *window); 33 | 34 | G_END_DECLS 35 | -------------------------------------------------------------------------------- /libportal/portal-helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * Copyright (C) 2024 GNOME Foundation, Inc. 4 | * 5 | * This file is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, version 3.0 of the 8 | * License. 9 | * 10 | * This file is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program. If not, see . 17 | * 18 | * SPDX-License-Identifier: LGPL-3.0-only 19 | * 20 | * Authors: 21 | * Matthias Clasen 22 | * Hubert Figuière 23 | */ 24 | 25 | #pragma once 26 | 27 | #include 28 | 29 | #include 30 | 31 | G_BEGIN_DECLS 32 | 33 | #ifndef XDP_PUBLIC 34 | #define XDP_PUBLIC extern 35 | #endif 36 | 37 | #define XDP_TYPE_PORTAL (xdp_portal_get_type ()) 38 | 39 | XDP_PUBLIC 40 | G_DECLARE_FINAL_TYPE (XdpPortal, xdp_portal, XDP, PORTAL, GObject) 41 | 42 | XDP_PUBLIC 43 | XdpPortal *xdp_portal_new (void); 44 | 45 | XDP_PUBLIC 46 | XdpPortal *xdp_portal_initable_new (GError **error); 47 | 48 | XDP_PUBLIC 49 | gboolean xdp_portal_running_under_flatpak (void); 50 | 51 | XDP_PUBLIC 52 | gboolean xdp_portal_running_under_snap (GError **error); 53 | 54 | XDP_PUBLIC 55 | gboolean xdp_portal_running_under_sandbox (void); 56 | 57 | XDP_PUBLIC 58 | XdpSettings *xdp_portal_get_settings (XdpPortal *portal); 59 | 60 | G_END_DECLS 61 | -------------------------------------------------------------------------------- /libportal/portal-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include "glib-backports.h" 23 | #include "parent-private.h" 24 | #include "portal-helpers.h" 25 | 26 | struct _XdpPortal { 27 | GObject parent_instance; 28 | 29 | GError *init_error; 30 | GDBusConnection *bus; 31 | char *sender; 32 | 33 | /* inhibit */ 34 | int next_inhibit_id; 35 | GHashTable *inhibit_handles; 36 | char *session_monitor_handle; 37 | guint state_changed_signal; 38 | 39 | /* spawn */ 40 | guint spawn_exited_signal; 41 | 42 | /* updates */ 43 | char *update_monitor_handle; 44 | guint update_available_signal; 45 | guint update_progress_signal; 46 | 47 | /* location */ 48 | char *location_monitor_handle; 49 | guint location_updated_signal; 50 | 51 | /* notification */ 52 | guint action_invoked_signal; 53 | guint notification_interface_version; 54 | GVariant *supported_notification_options; 55 | 56 | /* screencast */ 57 | guint screencast_interface_version; 58 | guint remote_desktop_interface_version; 59 | 60 | /* background */ 61 | guint background_interface_version; 62 | }; 63 | 64 | const char * portal_get_bus_name (void); 65 | 66 | #define PORTAL_BUS_NAME (portal_get_bus_name ()) 67 | #define PORTAL_OBJECT_PATH "/org/freedesktop/portal/desktop" 68 | #define REQUEST_PATH_PREFIX "/org/freedesktop/portal/desktop/request/" 69 | #define SESSION_PATH_PREFIX "/org/freedesktop/portal/desktop/session/" 70 | #define REQUEST_INTERFACE "org.freedesktop.portal.Request" 71 | #define SESSION_INTERFACE "org.freedesktop.portal.Session" 72 | #define SETTINGS_INTERFACE "org.freedesktop.portal.Settings" 73 | 74 | #define FLATPAK_PORTAL_BUS_NAME "org.freedesktop.portal.Flatpak" 75 | #define FLATPAK_PORTAL_OBJECT_PATH "/org/freedesktop/portal/Flatpak" 76 | #define FLATPAK_PORTAL_INTERFACE "org.freedesktop.portal.Flatpak" 77 | -------------------------------------------------------------------------------- /libportal/portal-qt5.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2022, Jan Grulich 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | XDP_PUBLIC 31 | XdpParent *xdp_parent_new_qt (QWindow *window); 32 | 33 | namespace XdpQt { 34 | 35 | // Returns a global instance of XdpPortal object and takes care 36 | // of its deletion 37 | XDP_PUBLIC 38 | XdpPortal *globalPortalObject(); 39 | 40 | // Account portal helpers 41 | struct GetUserInformationResult { 42 | QString id; 43 | QString name; 44 | QString image; 45 | }; 46 | 47 | XDP_PUBLIC 48 | GetUserInformationResult getUserInformationResultFromGVariant(GVariant *variant); 49 | 50 | // FileChooser portal helpers 51 | enum FileChooserFilterRuleType{ 52 | Pattern = 0, 53 | Mimetype = 1 54 | }; 55 | 56 | struct FileChooserFilterRule { 57 | FileChooserFilterRuleType type; 58 | QString rule; 59 | }; 60 | 61 | struct FileChooserFilter { 62 | QString label; 63 | QList rules; 64 | }; 65 | 66 | struct FileChooserChoice { 67 | QString id; 68 | QString label; 69 | QMap options; 70 | QString selected; 71 | }; 72 | 73 | XDP_PUBLIC 74 | GVariant *filechooserFilesToGVariant(const QStringList &files); 75 | 76 | XDP_PUBLIC 77 | GVariant *filechooserFilterToGVariant(const FileChooserFilter &filter); 78 | 79 | XDP_PUBLIC 80 | GVariant *filechooserFiltersToGVariant(const QList &filters); 81 | 82 | XDP_PUBLIC 83 | GVariant *filechooserChoicesToGVariant(const QList &choices); 84 | 85 | struct FileChooserResult { 86 | QMap choices; 87 | QStringList uris; 88 | }; 89 | 90 | XDP_PUBLIC 91 | FileChooserResult filechooserResultFromGVariant(GVariant *variant); 92 | 93 | // Notification portal helpers 94 | struct NotificationButton { 95 | QString label; 96 | QString action; 97 | QVariant target; 98 | }; 99 | 100 | struct Notification { 101 | QString title; 102 | QString body; 103 | QString icon; 104 | QPixmap pixmap; 105 | QString priority; 106 | QString defaultAction; 107 | QVariant defaultTarget; 108 | QList buttons; 109 | }; 110 | 111 | XDP_PUBLIC 112 | GVariant *notificationToGVariant(const Notification ¬ification); 113 | 114 | XDP_PUBLIC 115 | QVariant GVariantToQVariant(GVariant *variant); 116 | 117 | } // namespace XdpQt 118 | -------------------------------------------------------------------------------- /libportal/portal-qt6.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020-2022, Jan Grulich 3 | * Copyright (C) 2023, Neal Gompa 4 | * 5 | * This file is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, version 3.0 of the 8 | * License. 9 | * 10 | * This file is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program. If not, see . 17 | * 18 | * SPDX-License-Identifier: LGPL-3.0-only 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | XDP_PUBLIC 32 | XdpParent *xdp_parent_new_qt (QWindow *window); 33 | 34 | namespace XdpQt { 35 | 36 | // Returns a global instance of XdpPortal object and takes care 37 | // of its deletion 38 | XDP_PUBLIC 39 | XdpPortal *globalPortalObject(); 40 | 41 | // Account portal helpers 42 | struct GetUserInformationResult { 43 | QString id; 44 | QString name; 45 | QString image; 46 | }; 47 | 48 | XDP_PUBLIC 49 | GetUserInformationResult getUserInformationResultFromGVariant(GVariant *variant); 50 | 51 | // FileChooser portal helpers 52 | enum FileChooserFilterRuleType{ 53 | Pattern = 0, 54 | Mimetype = 1 55 | }; 56 | 57 | struct FileChooserFilterRule { 58 | FileChooserFilterRuleType type; 59 | QString rule; 60 | }; 61 | 62 | struct FileChooserFilter { 63 | QString label; 64 | QList rules; 65 | }; 66 | 67 | struct FileChooserChoice { 68 | QString id; 69 | QString label; 70 | QMap options; 71 | QString selected; 72 | }; 73 | 74 | XDP_PUBLIC 75 | GVariant *filechooserFilesToGVariant(const QStringList &files); 76 | 77 | XDP_PUBLIC 78 | GVariant *filechooserFilterToGVariant(const FileChooserFilter &filter); 79 | 80 | XDP_PUBLIC 81 | GVariant *filechooserFiltersToGVariant(const QList &filters); 82 | 83 | XDP_PUBLIC 84 | GVariant *filechooserChoicesToGVariant(const QList &choices); 85 | 86 | struct FileChooserResult { 87 | QMap choices; 88 | QStringList uris; 89 | }; 90 | 91 | XDP_PUBLIC 92 | FileChooserResult filechooserResultFromGVariant(GVariant *variant); 93 | 94 | // Notification portal helpers 95 | struct NotificationButton { 96 | QString label; 97 | QString action; 98 | QVariant target; 99 | }; 100 | 101 | struct Notification { 102 | QString title; 103 | QString body; 104 | QString icon; 105 | QPixmap pixmap; 106 | QString priority; 107 | QString defaultAction; 108 | QVariant defaultTarget; 109 | QList buttons; 110 | }; 111 | 112 | XDP_PUBLIC 113 | GVariant *notificationToGVariant(const Notification ¬ification); 114 | 115 | XDP_PUBLIC 116 | QVariant GVariantToQVariant(GVariant *variant); 117 | 118 | } // namespace XdpQt 119 | -------------------------------------------------------------------------------- /libportal/portal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | -------------------------------------------------------------------------------- /libportal/print.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef enum { 27 | XDP_PRINT_FLAG_NONE = 0 28 | } XdpPrintFlags; 29 | 30 | XDP_PUBLIC 31 | void xdp_portal_prepare_print (XdpPortal *portal, 32 | XdpParent *parent, 33 | const char *title, 34 | GVariant *settings, 35 | GVariant *page_setup, 36 | XdpPrintFlags flags, 37 | GCancellable *cancellable, 38 | GAsyncReadyCallback callback, 39 | gpointer data); 40 | 41 | XDP_PUBLIC 42 | GVariant *xdp_portal_prepare_print_finish (XdpPortal *portal, 43 | GAsyncResult *result, 44 | GError **error); 45 | 46 | XDP_PUBLIC 47 | void xdp_portal_print_file (XdpPortal *portal, 48 | XdpParent *parent, 49 | const char *title, 50 | guint token, 51 | const char *file, 52 | XdpPrintFlags flags, 53 | GCancellable *cancellable, 54 | GAsyncReadyCallback callback, 55 | gpointer data); 56 | 57 | XDP_PUBLIC 58 | gboolean xdp_portal_print_file_finish (XdpPortal *portal, 59 | GAsyncResult *result, 60 | GError **error); 61 | 62 | G_END_DECLS 63 | -------------------------------------------------------------------------------- /libportal/screenshot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | typedef enum { 27 | XDP_SCREENSHOT_FLAG_NONE = 0, 28 | XDP_SCREENSHOT_FLAG_INTERACTIVE = 1 << 0 29 | } XdpScreenshotFlags; 30 | 31 | XDP_PUBLIC 32 | void xdp_portal_take_screenshot (XdpPortal *portal, 33 | XdpParent *parent, 34 | XdpScreenshotFlags flags, 35 | GCancellable *cancellable, 36 | GAsyncReadyCallback callback, 37 | gpointer data); 38 | 39 | XDP_PUBLIC 40 | char * xdp_portal_take_screenshot_finish (XdpPortal *portal, 41 | GAsyncResult *result, 42 | GError **error); 43 | 44 | XDP_PUBLIC 45 | void xdp_portal_pick_color (XdpPortal *portal, 46 | XdpParent *parent, 47 | GCancellable *cancellable, 48 | GAsyncReadyCallback callback, 49 | gpointer data); 50 | 51 | XDP_PUBLIC 52 | GVariant * xdp_portal_pick_color_finish (XdpPortal *portal, 53 | GAsyncResult *result, 54 | GError **error); 55 | 56 | G_END_DECLS 57 | -------------------------------------------------------------------------------- /libportal/session-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | 25 | struct _XdpSession { 26 | GObject parent_instance; 27 | 28 | /* Generic Session implementation */ 29 | XdpPortal *portal; 30 | char *id; 31 | gboolean is_closed; 32 | XdpSessionType type; 33 | guint signal_id; 34 | 35 | /* RemoteDesktop/ScreenCast */ 36 | XdpSessionState state; 37 | XdpDeviceType devices; 38 | GVariant *streams; 39 | 40 | XdpPersistMode persist_mode; 41 | char *restore_token; 42 | 43 | gboolean uses_eis; 44 | 45 | /* InputCapture */ 46 | XdpInputCaptureSession *input_capture_session; /* weak ref */ 47 | }; 48 | 49 | XdpSession * _xdp_session_new (XdpPortal *portal, 50 | const char *id, 51 | XdpSessionType type); 52 | 53 | void _xdp_session_set_session_state (XdpSession *session, 54 | XdpSessionState state); 55 | 56 | void _xdp_session_set_devices (XdpSession *session, 57 | XdpDeviceType devices); 58 | 59 | void _xdp_session_set_streams (XdpSession *session, 60 | GVariant *streams); 61 | 62 | void _xdp_session_close (XdpSession *session); 63 | -------------------------------------------------------------------------------- /libportal/session.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include "session-private.h" 23 | #include "portal-private.h" 24 | 25 | /** 26 | * XdpSession 27 | * 28 | * A representation of long-lived screencast portal interactions. 29 | * 30 | * The XdpSession object is used to represent portal interactions with the 31 | * screencast or remote desktop portals that extend over multiple portal calls. 32 | * 33 | * To find out what kind of session an XdpSession object represents and whether 34 | * it is still active, you can use [method@Session.get_session_type] and 35 | * [method@Session.get_session_state]. 36 | * 37 | * All sessions start in an initial state. They can be made active by calling 38 | * [method@Session.start], and ended by calling [method@Session.close]. 39 | */ 40 | enum { 41 | CLOSED, 42 | LAST_SIGNAL 43 | }; 44 | 45 | static guint signals[LAST_SIGNAL]; 46 | 47 | G_DEFINE_TYPE (XdpSession, xdp_session, G_TYPE_OBJECT) 48 | 49 | static void 50 | xdp_session_finalize (GObject *object) 51 | { 52 | XdpSession *session = XDP_SESSION (object); 53 | 54 | if (session->signal_id) 55 | g_dbus_connection_signal_unsubscribe (session->portal->bus, session->signal_id); 56 | 57 | g_clear_object (&session->portal); 58 | g_clear_pointer (&session->restore_token, g_free); 59 | g_clear_pointer (&session->id, g_free); 60 | g_clear_pointer (&session->streams, g_variant_unref); 61 | if (session->input_capture_session != NULL) 62 | g_critical ("XdpSession destroyed before XdpInputCaptureSesssion, you lost count of your session refs"); 63 | session->input_capture_session = NULL; 64 | 65 | G_OBJECT_CLASS (xdp_session_parent_class)->finalize (object); 66 | } 67 | 68 | static void 69 | xdp_session_class_init (XdpSessionClass *klass) 70 | { 71 | GObjectClass *object_class = G_OBJECT_CLASS (klass); 72 | 73 | object_class->finalize = xdp_session_finalize; 74 | 75 | /** 76 | * XdpSession::closed: 77 | * 78 | * Emitted when a session is closed externally. 79 | */ 80 | signals[CLOSED] = 81 | g_signal_new ("closed", 82 | G_TYPE_FROM_CLASS (object_class), 83 | G_SIGNAL_RUN_CLEANUP | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 84 | 0, 85 | NULL, NULL, 86 | NULL, 87 | G_TYPE_NONE, 0); 88 | } 89 | 90 | static void 91 | xdp_session_init (XdpSession *session) 92 | { 93 | } 94 | 95 | static void 96 | session_closed (GDBusConnection *bus, 97 | const char *sender_name, 98 | const char *object_path, 99 | const char *interface_name, 100 | const char *signal_name, 101 | GVariant *parameters, 102 | gpointer data) 103 | { 104 | XdpSession *session = data; 105 | 106 | _xdp_session_set_session_state (session, XDP_SESSION_CLOSED); 107 | } 108 | 109 | XdpSession * 110 | _xdp_session_new (XdpPortal *portal, 111 | const char *id, 112 | XdpSessionType type) 113 | { 114 | XdpSession *session; 115 | 116 | session = g_object_new (XDP_TYPE_SESSION, NULL); 117 | session->portal = g_object_ref (portal); 118 | session->id = g_strdup (id); 119 | session->type = type; 120 | session->state = XDP_SESSION_INITIAL; 121 | session->input_capture_session = NULL; 122 | 123 | session->signal_id = g_dbus_connection_signal_subscribe (portal->bus, 124 | PORTAL_BUS_NAME, 125 | SESSION_INTERFACE, 126 | "Closed", 127 | id, 128 | NULL, 129 | G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE, 130 | session_closed, 131 | session, 132 | NULL); 133 | return session; 134 | } 135 | 136 | void 137 | _xdp_session_close (XdpSession *session) 138 | { 139 | if (session->is_closed) 140 | return; 141 | 142 | session->is_closed = TRUE; 143 | g_signal_emit_by_name (session, "closed"); 144 | } 145 | 146 | /** 147 | * xdp_session_get_session_type: 148 | * @session: an [class@Session] 149 | * 150 | * Obtains information about the type of session that is represented 151 | * by @session. 152 | * 153 | * Returns: the type of @session 154 | */ 155 | XdpSessionType 156 | xdp_session_get_session_type (XdpSession *session) 157 | { 158 | g_return_val_if_fail (XDP_IS_SESSION (session), XDP_SESSION_SCREENCAST); 159 | 160 | return session->type; 161 | } 162 | 163 | /** 164 | * xdp_session_close: 165 | * @session: an active [class@Session] 166 | * 167 | * Closes the session. 168 | */ 169 | void 170 | xdp_session_close (XdpSession *session) 171 | { 172 | g_return_if_fail (XDP_IS_SESSION (session)); 173 | 174 | g_dbus_connection_call (session->portal->bus, 175 | PORTAL_BUS_NAME, 176 | session->id, 177 | SESSION_INTERFACE, 178 | "Close", 179 | NULL, 180 | NULL, 0, -1, NULL, NULL, NULL); 181 | 182 | _xdp_session_set_session_state (session, XDP_SESSION_CLOSED); 183 | _xdp_session_close (session); 184 | } 185 | -------------------------------------------------------------------------------- /libportal/session.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | #define XDP_TYPE_SESSION (xdp_session_get_type ()) 27 | 28 | XDP_PUBLIC 29 | G_DECLARE_FINAL_TYPE (XdpSession, xdp_session, XDP, SESSION, GObject) 30 | 31 | /** 32 | * XdpSessionType: 33 | * @XDP_SESSION_SCREENCAST: a screencast session. 34 | * @XDP_SESSION_REMOTE_DESKTOP: a remote desktop session. 35 | * @XDP_SESSION_INPUT_CAPTURE: an input capture session. 36 | * 37 | * The type of a session. 38 | */ 39 | typedef enum { 40 | XDP_SESSION_SCREENCAST, 41 | XDP_SESSION_REMOTE_DESKTOP, 42 | XDP_SESSION_INPUT_CAPTURE, 43 | } XdpSessionType; 44 | 45 | XDP_PUBLIC 46 | void xdp_session_close (XdpSession *session); 47 | 48 | XDP_PUBLIC 49 | XdpSessionType xdp_session_get_session_type (XdpSession *session); 50 | 51 | G_END_DECLS 52 | -------------------------------------------------------------------------------- /libportal/settings-private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 GNOME Foundation, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | * 19 | * Authors: 20 | * Hubert Figuière 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | #include "settings.h" 28 | 29 | G_BEGIN_DECLS 30 | 31 | XdpSettings * _xdp_settings_new (XdpPortal *portal); 32 | 33 | G_END_DECLS 34 | -------------------------------------------------------------------------------- /libportal/settings.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2024 GNOME Foundation, Inc. 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | * 19 | * Authors: 20 | * Hubert Figuière 21 | */ 22 | 23 | #pragma once 24 | 25 | #include 26 | 27 | G_BEGIN_DECLS 28 | 29 | #define XDP_TYPE_SETTINGS (xdp_settings_get_type ()) 30 | 31 | XDP_PUBLIC 32 | G_DECLARE_FINAL_TYPE (XdpSettings, xdp_settings, XDP, SETTINGS, GObject) 33 | 34 | XDP_PUBLIC 35 | GVariant *xdp_settings_read_value (XdpSettings *settings, const char *namespace, const char *key, GCancellable *cancellable, GError **error); 36 | 37 | XDP_PUBLIC 38 | void 39 | xdp_settings_read (XdpSettings *settings, const char *namespace, 40 | const gchar *key, 41 | GCancellable *cancellable, GError **error, 42 | const gchar *format, ...); 43 | 44 | XDP_PUBLIC 45 | guint xdp_settings_read_uint (XdpSettings *settings, const char *namespace, const char *key, GCancellable *cancellable, GError **error); 46 | 47 | XDP_PUBLIC 48 | char *xdp_settings_read_string (XdpSettings *settings, const char *namespace, const char *key, GCancellable *cancellable, GError **error); 49 | 50 | XDP_PUBLIC 51 | GVariant *xdp_settings_read_all_values (XdpSettings *settings, const char *const *namespaces, GCancellable *cancellable, GError **error); 52 | 53 | G_END_DECLS 54 | -------------------------------------------------------------------------------- /libportal/spawn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpSpawnFlags: 28 | * @XDP_SPAWN_FLAG_NONE: No flags 29 | * @XDP_SPAWN_FLAG_CLEARENV: Clear the environment 30 | * @XDP_SPAWN_FLAG_LATEST: Spawn the latest version of the app 31 | * @XDP_SPAWN_FLAG_SANDBOX: Spawn in a sandbox (equivalent to the --sandbox option of flatpak run) 32 | * @XDP_SPAWN_FLAG_NO_NETWORK: Spawn without network (equivalent to the --unshare=network option of flatpak run) 33 | * @XDP_SPAWN_FLAG_WATCH: Kill the sandbox when the caller disappears from the session bus 34 | * 35 | * Flags influencing the spawn operation and how the 36 | * new sandbox is created. 37 | */ 38 | typedef enum { 39 | XDP_SPAWN_FLAG_NONE = 0, 40 | XDP_SPAWN_FLAG_CLEARENV = 1 << 0, 41 | XDP_SPAWN_FLAG_LATEST = 1 << 1, 42 | XDP_SPAWN_FLAG_SANDBOX = 1 << 2, 43 | XDP_SPAWN_FLAG_NO_NETWORK = 1 << 3, 44 | XDP_SPAWN_FLAG_WATCH = 1 << 4, 45 | } XdpSpawnFlags; 46 | 47 | XDP_PUBLIC 48 | void xdp_portal_spawn (XdpPortal *portal, 49 | const char *cwd, 50 | const char * const *argv, 51 | int *fds, 52 | int *map_to, 53 | int n_fds, 54 | const char * const *env, 55 | XdpSpawnFlags flags, 56 | const char * const *sandbox_expose, 57 | const char * const *sandbox_expose_ro, 58 | GCancellable *cancellable, 59 | GAsyncReadyCallback callback, 60 | gpointer data); 61 | 62 | XDP_PUBLIC 63 | pid_t xdp_portal_spawn_finish (XdpPortal *portal, 64 | GAsyncResult *result, 65 | GError **error); 66 | 67 | XDP_PUBLIC 68 | void xdp_portal_spawn_signal (XdpPortal *portal, 69 | pid_t pid, 70 | int signal, 71 | gboolean to_process_group); 72 | 73 | G_END_DECLS 74 | -------------------------------------------------------------------------------- /libportal/trash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #include "config.h" 21 | 22 | #include "trash.h" 23 | 24 | #define GNU_SOURCE 1 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | 33 | #include "portal-private.h" 34 | 35 | typedef struct { 36 | XdpPortal *portal; 37 | char *path; 38 | GTask *task; 39 | } TrashCall; 40 | 41 | static void 42 | trash_call_free (TrashCall *call) 43 | { 44 | g_object_unref (call->portal); 45 | g_object_unref (call->task); 46 | g_free (call->path); 47 | 48 | g_free (call); 49 | } 50 | 51 | #ifndef O_PATH 52 | #define O_PATH 0 53 | #endif 54 | 55 | static void 56 | file_trashed (GObject *bus, 57 | GAsyncResult *result, 58 | gpointer data) 59 | { 60 | GError *error = NULL; 61 | g_autoptr(GVariant) ret = NULL; 62 | TrashCall *call = data; 63 | 64 | ret = g_dbus_connection_call_with_unix_fd_list_finish (G_DBUS_CONNECTION (bus), 65 | NULL, 66 | result, 67 | &error); 68 | if (error) 69 | g_task_return_error (call->task, error); 70 | else 71 | { 72 | guint retval; 73 | 74 | g_variant_get (ret, "(u)", &retval); 75 | 76 | if (retval == 1) 77 | g_task_return_boolean (call->task, TRUE); 78 | else 79 | g_task_return_new_error (call->task, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to trash"); 80 | } 81 | 82 | trash_call_free (call); 83 | } 84 | 85 | static void 86 | trash_file (TrashCall *call) 87 | { 88 | g_autoptr(GUnixFDList) fd_list = NULL; 89 | int fd, fd_in; 90 | GCancellable *cancellable; 91 | 92 | fd = g_open (call->path, O_PATH | O_CLOEXEC); 93 | if (fd == -1) 94 | { 95 | g_task_return_new_error (call->task, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to open '%s'", call->path); 96 | trash_call_free (call); 97 | return; 98 | } 99 | 100 | fd_list = g_unix_fd_list_new_from_array (&fd, 1); 101 | fd = -1; 102 | fd_in = 0; 103 | 104 | cancellable = g_task_get_cancellable (call->task); 105 | 106 | g_dbus_connection_call_with_unix_fd_list (call->portal->bus, 107 | PORTAL_BUS_NAME, 108 | PORTAL_OBJECT_PATH, 109 | "org.freedesktop.portal.Trash", 110 | "TrashFile", 111 | g_variant_new ("(h)", fd_in), 112 | NULL, 113 | G_DBUS_CALL_FLAGS_NONE, 114 | -1, 115 | fd_list, 116 | cancellable, 117 | file_trashed, 118 | call); 119 | 120 | } 121 | 122 | /** 123 | * xdp_portal_trash_file: 124 | * @portal: a [class@Portal] 125 | * @path: the path for a local file 126 | * @cancellable: (nullable): optional [class@Gio.Cancellable] 127 | * @callback: (scope async): a callback to call when the request is done 128 | * @data: data to pass to @callback 129 | * 130 | * Sends the file at @path to the trash can. 131 | */ 132 | void 133 | xdp_portal_trash_file (XdpPortal *portal, 134 | const char *path, 135 | GCancellable *cancellable, 136 | GAsyncReadyCallback callback, 137 | gpointer data) 138 | 139 | { 140 | TrashCall *call; 141 | 142 | g_return_if_fail (XDP_IS_PORTAL (portal)); 143 | g_return_if_fail (path != NULL); 144 | 145 | call = g_new0 (TrashCall, 1); 146 | call->portal = g_object_ref (portal); 147 | call->path = g_strdup (path); 148 | call->task = g_task_new (portal, cancellable, callback, data); 149 | g_task_set_source_tag (call->task, xdp_portal_trash_file); 150 | 151 | trash_file (call); 152 | } 153 | 154 | /** 155 | * xdp_portal_trash_file_finish: 156 | * @portal: a [class@Portal] 157 | * @result: a [iface@Gio.AsyncResult] 158 | * @error: return location for an error 159 | * 160 | * Finishes the trash-file request. 161 | * 162 | * Returns the result in the form of a boolean. 163 | * 164 | * Returns: `TRUE` if the call succeeded 165 | */ 166 | gboolean 167 | xdp_portal_trash_file_finish (XdpPortal *portal, 168 | GAsyncResult *result, 169 | GError **error) 170 | { 171 | g_return_val_if_fail (XDP_IS_PORTAL (portal), FALSE); 172 | g_return_val_if_fail (g_task_is_valid (result, portal), FALSE); 173 | g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == xdp_portal_trash_file, FALSE); 174 | 175 | return g_task_propagate_boolean (G_TASK (result), error); 176 | } 177 | -------------------------------------------------------------------------------- /libportal/trash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | XDP_PUBLIC 27 | void xdp_portal_trash_file (XdpPortal *portal, 28 | const char *path, 29 | GCancellable *cancellable, 30 | GAsyncReadyCallback callback, 31 | gpointer data); 32 | 33 | XDP_PUBLIC 34 | gboolean xdp_portal_trash_file_finish (XdpPortal *portal, 35 | GAsyncResult *result, 36 | GError **error); 37 | 38 | G_END_DECLS 39 | -------------------------------------------------------------------------------- /libportal/types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021, Georges Basile Stavracas Neto 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | typedef struct _XdpParent XdpParent; 27 | typedef struct _XdpPortal XdpPortal; 28 | typedef struct _XdpSettings XdpSettings; 29 | -------------------------------------------------------------------------------- /libportal/updates.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpUpdateStatus: 28 | * @XDP_UPDATE_STATUS_RUNNING: Installation in progress 29 | * @XDP_UPDATE_STATUS_EMPTY: Nothing to install 30 | * @XDP_UPDATE_STATUS_DONE: Installation finished successfully 31 | * @XDP_UPDATE_STATUS_FAILED: Installation failed 32 | * 33 | * The values of this enum are returned in the 34 | * [signal@Portal::update-progress] signal to indicate 35 | * the current progress of an installation. 36 | */ 37 | typedef enum { 38 | XDP_UPDATE_STATUS_RUNNING, 39 | XDP_UPDATE_STATUS_EMPTY, 40 | XDP_UPDATE_STATUS_DONE, 41 | XDP_UPDATE_STATUS_FAILED 42 | } XdpUpdateStatus; 43 | 44 | typedef enum 45 | { 46 | XDP_UPDATE_MONITOR_FLAG_NONE = 0, 47 | } XdpUpdateMonitorFlags; 48 | 49 | XDP_PUBLIC 50 | void xdp_portal_update_monitor_start (XdpPortal *portal, 51 | XdpUpdateMonitorFlags flags, 52 | GCancellable *cancellable, 53 | GAsyncReadyCallback callback, 54 | gpointer data); 55 | 56 | XDP_PUBLIC 57 | gboolean xdp_portal_update_monitor_start_finish (XdpPortal *portal, 58 | GAsyncResult *result, 59 | GError **error); 60 | 61 | XDP_PUBLIC 62 | void xdp_portal_update_monitor_stop (XdpPortal *portal); 63 | 64 | typedef enum 65 | { 66 | XDP_UPDATE_INSTALL_FLAG_NONE = 0, 67 | } XdpUpdateInstallFlags; 68 | 69 | XDP_PUBLIC 70 | void xdp_portal_update_install (XdpPortal *portal, 71 | XdpParent *parent, 72 | XdpUpdateInstallFlags flags, 73 | GCancellable *cancellable, 74 | GAsyncReadyCallback callback, 75 | gpointer data); 76 | 77 | XDP_PUBLIC 78 | gboolean xdp_portal_update_install_finish (XdpPortal *portal, 79 | GAsyncResult *result, 80 | GError **error); 81 | 82 | G_END_DECLS 83 | -------------------------------------------------------------------------------- /libportal/wallpaper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019, Matthias Clasen 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | G_BEGIN_DECLS 25 | 26 | /** 27 | * XdpWallpaperFlags: 28 | * @XDP_WALLPAPER_FLAG_NONE: No flags 29 | * @XDP_WALLPAPER_FLAG_BACKGROUND: Set wallpaper on the desktop background 30 | * @XDP_WALLPAPER_FLAG_LOCKSCREEN: Set wallpaper on the lockscreen 31 | * @XDP_WALLPAPER_FLAG_PREVIEW: Request the preview to be shown 32 | * 33 | * The values of this enumeration determine where the wallpaper is being set. 34 | */ 35 | typedef enum { 36 | XDP_WALLPAPER_FLAG_NONE = 0, 37 | XDP_WALLPAPER_FLAG_BACKGROUND = 1 << 0, 38 | XDP_WALLPAPER_FLAG_LOCKSCREEN = 1 << 1, 39 | XDP_WALLPAPER_FLAG_PREVIEW = 1 << 2 40 | } XdpWallpaperFlags; 41 | 42 | #define XDP_WALLPAPER_TARGET_BOTH (XDP_WALLPAPER_TARGET_BACKGROUND|XDP_WALLPAPER_TARGET_LOCKSCREEN) 43 | 44 | XDP_PUBLIC 45 | void xdp_portal_set_wallpaper (XdpPortal *portal, 46 | XdpParent *parent, 47 | const char *uri, 48 | XdpWallpaperFlags flags, 49 | GCancellable *cancellable, 50 | GAsyncReadyCallback callback, 51 | gpointer data); 52 | 53 | XDP_PUBLIC 54 | gboolean xdp_portal_set_wallpaper_finish (XdpPortal *portal, 55 | GAsyncResult *result, 56 | GError **error); 57 | 58 | G_END_DECLS 59 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('libportal','c', 2 | version: '0.9.2', 3 | default_options: ['warning_level=2'], 4 | meson_version: '>= 0.55.0') 5 | 6 | cc = meson.get_compiler('c') 7 | cflags = [ 8 | '-Wno-unused-parameter', 9 | '-Wno-missing-field-initializers', 10 | ] 11 | add_project_arguments(cc.get_supported_arguments(cflags), language: 'c') 12 | 13 | gnome = import('gnome') 14 | pkgconfig = import('pkgconfig') 15 | 16 | qt5 = import('qt5') 17 | 18 | if get_option('backend-qt6').enabled() and meson.version().version_compare('< 0.59.0') 19 | error('qt6 backend requires meson 0.59.0 or newer') 20 | endif 21 | 22 | if meson.version().version_compare('>= 0.59.0') 23 | qt6 = import('qt6') 24 | endif 25 | 26 | conf = configuration_data() 27 | conf.set_quoted('G_LOG_DOMAIN', 'libportal') 28 | conf.set_quoted('PACKAGE_NAME', 'libportal') 29 | conf.set_quoted('PKGDATADIR', join_paths(get_option('prefix'), get_option('datadir'), 'libportal')) 30 | conf.set_quoted('APPDATADIR', join_paths(get_option('prefix'), get_option('datadir'), 'org.gnome.PortalTest')) 31 | 32 | if cc.has_argument('-fvisibility=hidden') 33 | conf.set('XDP_PUBLIC', '__attribute__((visibility("default"))) extern') 34 | endif 35 | 36 | check_headers = ['sys/vfs.h'] 37 | 38 | foreach header : check_headers 39 | macro = 'HAVE_' + header.underscorify().to_upper() 40 | conf.set(macro, cc.has_header(header) ? 1 : false) 41 | endforeach 42 | 43 | configure_file(output : 'config.h', configuration : conf) 44 | 45 | introspection = get_option('introspection') 46 | vapi = get_option('vapi') 47 | 48 | top_inc = include_directories('.') 49 | libportal_inc = include_directories('libportal') 50 | 51 | subdir('libportal') 52 | 53 | if get_option('portal-tests') 54 | subdir('portal-test') 55 | endif 56 | 57 | if get_option('tests') 58 | subdir('tests') 59 | endif 60 | 61 | if get_option('docs') 62 | subdir('doc') 63 | endif 64 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('backend-gtk3', type: 'feature', value: 'auto', 2 | description: 'Build the GTK3 portal backend') 3 | option('backend-gtk4', type: 'feature', value: 'auto', 4 | description: 'Build the GTK4 portal backend') 5 | option('backend-qt5', type: 'feature', value: 'auto', 6 | description: 'Build the Qt5 portal backend') 7 | option('backend-qt6', type: 'feature', value: 'auto', 8 | description: 'Build the Qt6 portal backend') 9 | option('portal-tests', type: 'boolean', value: false, 10 | description : 'Build portal tests of each backend') 11 | option('introspection', type: 'boolean', value: true, 12 | description: 'Generate GObject introspection files') 13 | option('vapi', type: 'boolean', value: true, 14 | description : 'Generate Vala bindings') 15 | option('docs', type: 'boolean', value: true, 16 | description : 'Build API reference with gi-docgen') 17 | option('tests', type: 'boolean', value: true, 18 | description : 'Build unit tests') 19 | -------------------------------------------------------------------------------- /portal-test/gtk3/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "portal-test-app.h" 5 | 6 | int 7 | main (int argc, char *argv[]) 8 | { 9 | gst_init (&argc, &argv); 10 | 11 | g_message ("Starting org.gnome.PortalTest.Gtk3"); 12 | 13 | if (g_strv_contains ((const char * const *)argv, "--replace")) 14 | portal_test_app_stop_running_instance (); 15 | 16 | return g_application_run (portal_test_app_new (), argc, argv); 17 | } 18 | -------------------------------------------------------------------------------- /portal-test/gtk3/meson.build: -------------------------------------------------------------------------------- 1 | 2 | gst_dep = dependency('gstreamer-audio-1.0') 3 | 4 | resources = gnome.compile_resources('resources', 5 | 'portal-test.gresource.xml', 6 | c_name: '_portal_test', 7 | ) 8 | 9 | src = [ 10 | 'main.c', 11 | 'portal-test-app.h', 12 | 'portal-test-app.c', 13 | 'portal-test-win.h', 14 | 'portal-test-win.c', 15 | resources, 16 | ] 17 | 18 | portal_test_gtk3 = executable('portal-test-gtk3', 19 | src, 20 | include_directories: [top_inc, libportal_inc], 21 | dependencies: [gst_dep, libportal_gtk3_dep], 22 | install : true, 23 | ) 24 | 25 | install_data('test.txt', install_dir: 'share/org.gnome.PortalTest.Gtk3') 26 | install_data('org.gnome.PortalTest.Gtk3.desktop', install_dir: 'share/applications') 27 | install_data('org.gnome.PortalTest.Gtk3.service', install_dir: 'share/dbus-1/services') 28 | 29 | executable('portal-linking-test-gtk3', 30 | [ 'portal-linking-test.c' ], 31 | include_directories: [libportal_inc], 32 | dependencies: [libportal_gtk3_dep], 33 | ) 34 | 35 | if meson.can_run_host_binaries() 36 | run_target('portal-test-gtk3', 37 | command: portal_test_gtk3, 38 | ) 39 | endif 40 | -------------------------------------------------------------------------------- /portal-test/gtk3/org.gnome.PortalTest.Gtk3.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Portal test (GTK3) 3 | Exec=portal-test-gtk3 4 | Type=Application 5 | DBusActivatable=true 6 | -------------------------------------------------------------------------------- /portal-test/gtk3/org.gnome.PortalTest.Gtk3.service: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=org.gnome.PortalTest.Gtk3 3 | Exec=portal-test-gtk3 4 | -------------------------------------------------------------------------------- /portal-test/gtk3/portal-linking-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | main (int argc, char **argv) 5 | { 6 | XdpPortal *portal; 7 | 8 | portal = xdp_portal_new (); 9 | (void) xdp_portal_is_camera_present (portal); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /portal-test/gtk3/portal-test-app.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "portal-test-app.h" 5 | #include "portal-test-win.h" 6 | 7 | struct _PortalTestApp 8 | { 9 | GtkApplication parent; 10 | }; 11 | 12 | struct _PortalTestAppClass 13 | { 14 | GtkApplicationClass parent_class; 15 | }; 16 | 17 | G_DEFINE_TYPE(PortalTestApp, portal_test_app, GTK_TYPE_APPLICATION) 18 | 19 | static void 20 | portal_test_app_init (PortalTestApp *app) 21 | { 22 | /* this option is handled explicitly in main(), 23 | * just add it here so GApplication is not surprised. 24 | */ 25 | g_application_add_main_option (G_APPLICATION (app), 26 | "replace", 27 | 0, 28 | G_OPTION_FLAG_NONE, 29 | G_OPTION_ARG_NONE, 30 | "Replace the running instance", NULL); 31 | } 32 | 33 | static void 34 | name_appeared (GDBusConnection *bus, 35 | const char *name, 36 | const char *name_owner, 37 | gpointer data) 38 | { 39 | gboolean *name_free = data; 40 | 41 | g_message ("Name %s owned by %s", name, name_owner); 42 | 43 | *name_free = FALSE; 44 | } 45 | 46 | static void 47 | name_vanished (GDBusConnection *bus, 48 | const char *name, 49 | gpointer data) 50 | { 51 | gboolean *name_free = data; 52 | 53 | g_message ("Name %s unowned", name); 54 | 55 | *name_free = TRUE; 56 | } 57 | 58 | void 59 | portal_test_app_stop_running_instance (void) 60 | { 61 | g_autoptr(GDBusConnection) bus = NULL; 62 | g_autoptr(GError) error = NULL; 63 | g_autoptr(GVariant) ret = NULL; 64 | GVariantBuilder options; 65 | GVariantBuilder pdata; 66 | guint watcher_id; 67 | gboolean name_free = FALSE; 68 | 69 | g_message ("Replacing the running instance"); 70 | 71 | /* Can't use g_application_activate_action here, 72 | * since we're not set up as a remote instance yet. 73 | */ 74 | bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); 75 | if (bus == NULL) 76 | { 77 | g_warning ("Failed to get session bus"); 78 | exit (1); 79 | } 80 | 81 | watcher_id = g_bus_watch_name_on_connection (bus, 82 | "org.gnome.PortalTest", 83 | 0, 84 | name_appeared, 85 | name_vanished, 86 | &name_free, 87 | NULL); 88 | 89 | g_variant_builder_init (&options, G_VARIANT_TYPE ("av")); 90 | g_variant_builder_init (&pdata, G_VARIANT_TYPE ("a{sv}")); 91 | ret = g_dbus_connection_call_sync (bus, 92 | "org.gnome.PortalTest", 93 | "/org/gnome/PortalTest", 94 | "org.gtk.Actions", 95 | "Activate", 96 | g_variant_new ("(sava{sv})", 97 | "quit", &options, &pdata), 98 | NULL, 99 | G_DBUS_CALL_FLAGS_NONE, 100 | -1, 101 | NULL, 102 | &error); 103 | if (error != NULL) 104 | { 105 | g_warning ("Failed to quit the running instance: %s", error->message); 106 | exit (1); 107 | } 108 | 109 | if (!name_free) 110 | g_message ("Waiting for running instance to give up name ownership"); 111 | 112 | while (!name_free) 113 | g_main_context_iteration (NULL, TRUE); 114 | 115 | g_bus_unwatch_name (watcher_id); 116 | } 117 | 118 | static void 119 | portal_test_app_startup (GApplication *app) 120 | { 121 | g_autoptr(GMenu) menu = NULL; 122 | 123 | G_APPLICATION_CLASS (portal_test_app_parent_class)->startup (app); 124 | 125 | menu = g_menu_new (); 126 | g_menu_append (menu, "Restart", "app.restart"); 127 | g_menu_append (menu, "Quit", "app.quit"); 128 | 129 | gtk_application_set_app_menu (GTK_APPLICATION (app), G_MENU_MODEL (menu)); 130 | } 131 | 132 | static void 133 | portal_test_app_activate (GApplication *app) 134 | { 135 | GtkWindow *win; 136 | 137 | win = gtk_application_get_active_window (GTK_APPLICATION (app)); 138 | if (!win) 139 | win = GTK_WINDOW (portal_test_win_new (PORTAL_TEST_APP (app))); 140 | gtk_window_present (win); 141 | } 142 | 143 | static void 144 | portal_test_app_class_init (PortalTestAppClass *class) 145 | { 146 | G_APPLICATION_CLASS (class)->startup = portal_test_app_startup; 147 | G_APPLICATION_CLASS (class)->activate = portal_test_app_activate; 148 | } 149 | 150 | static void 151 | acktivate (GSimpleAction *action, 152 | GVariant *parameter, 153 | gpointer user_data) 154 | { 155 | GtkApplication *app = user_data; 156 | GtkWindow *win; 157 | 158 | win = gtk_application_get_active_window (app); 159 | portal_test_win_ack (PORTAL_TEST_WIN (win)); 160 | } 161 | 162 | static void 163 | spawned_cb (GObject *source, 164 | GAsyncResult *res, 165 | gpointer data) 166 | { 167 | GDBusConnection *bus = G_DBUS_CONNECTION (source); 168 | g_autoptr(GError) error = NULL; 169 | g_autoptr(GVariant) ret = NULL; 170 | guint32 pid; 171 | 172 | ret = g_dbus_connection_call_finish (bus, res, &error); 173 | 174 | if (!ret) 175 | { 176 | g_warning ("Restart failed: %s\n", error->message); 177 | return; 178 | } 179 | 180 | g_variant_get (ret, "(u)", &pid); 181 | g_message ("Restarted with pid %d", pid); 182 | } 183 | 184 | void 185 | portal_test_app_restart (PortalTestApp *app) 186 | { 187 | GDBusConnection *bus; 188 | const char *strv[3] = { "portal-test", "--replace", NULL }; 189 | GVariant *args; 190 | 191 | bus = g_application_get_dbus_connection (G_APPLICATION (app)); 192 | 193 | g_message ("Calling org.freedesktop.portal.Flatpak.Spawn"); 194 | args = g_variant_new ("(@ay@aay@a{uh}@a{ss}u@a{sv})", 195 | g_variant_new_bytestring ("/"), 196 | g_variant_new_bytestring_array (strv, -1), 197 | g_variant_new_array (G_VARIANT_TYPE ("{uh}"), NULL, 0), 198 | g_variant_new_array (G_VARIANT_TYPE ("{ss}"), NULL, 0), 199 | 2, 200 | g_variant_new_array (G_VARIANT_TYPE ("{sv}"), NULL, 0)), 201 | 202 | g_dbus_connection_call (bus, 203 | "org.freedesktop.portal.Flatpak", 204 | "/org/freedesktop/portal/Flatpak", 205 | "org.freedesktop.portal.Flatpak", 206 | "Spawn", 207 | args, 208 | G_VARIANT_TYPE ("(u)"), 209 | 0, 210 | -1, 211 | NULL, 212 | spawned_cb, 213 | app); 214 | } 215 | 216 | static void 217 | restart (GSimpleAction *action, 218 | GVariant *parameter, 219 | gpointer user_data) 220 | { 221 | portal_test_app_restart (PORTAL_TEST_APP (user_data)); 222 | } 223 | 224 | static void 225 | quit (GSimpleAction *action, 226 | GVariant *parameter, 227 | gpointer user_data) 228 | { 229 | g_message ("Received a request to quit"); 230 | g_application_quit (G_APPLICATION (user_data)); 231 | } 232 | 233 | static GActionEntry entries[] = { 234 | { "ack", acktivate, NULL, NULL, NULL }, 235 | { "restart", restart, NULL, NULL, NULL }, 236 | { "quit", quit, NULL, NULL, NULL } 237 | }; 238 | 239 | GApplication * 240 | portal_test_app_new (void) 241 | { 242 | GApplication *app; 243 | 244 | app = g_object_new (portal_test_app_get_type (), 245 | "application-id", "org.gnome.PortalTest.Gtk3", 246 | NULL); 247 | 248 | g_action_map_add_action_entries (G_ACTION_MAP (app), entries, G_N_ELEMENTS (entries), app); 249 | 250 | return app; 251 | } 252 | -------------------------------------------------------------------------------- /portal-test/gtk3/portal-test-app.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | G_DECLARE_FINAL_TYPE(PortalTestApp, portal_test_app, PORTAL, TEST_APP, GtkApplication) 6 | 7 | GType portal_test_app_get_type (void); 8 | GApplication *portal_test_app_new (void); 9 | void portal_test_app_restart (PortalTestApp *app); 10 | void portal_test_app_stop_running_instance (void); 11 | -------------------------------------------------------------------------------- /portal-test/gtk3/portal-test-win.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "portal-test-app.h" 5 | 6 | G_DECLARE_FINAL_TYPE(PortalTestWin, portal_test_win, PORTAL, TEST_WIN, GtkApplicationWindow) 7 | 8 | GType portal_test_win_get_type (void); 9 | GtkApplicationWindow *portal_test_win_new (PortalTestApp *app); 10 | void portal_test_win_ack (PortalTestWin *win); 11 | -------------------------------------------------------------------------------- /portal-test/gtk3/portal-test.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | portal-test-win.ui 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /portal-test/gtk3/test.txt: -------------------------------------------------------------------------------- 1 | Like a trash can fire in a prison cell \\ 2 | like a search light in the parking lot of hell 3 | -------------------------------------------------------------------------------- /portal-test/gtk4/application.js: -------------------------------------------------------------------------------- 1 | const { Gio, GLib, GObject, Gtk } = imports.gi; 2 | 3 | const { PortalTestWindow } = imports.window; 4 | const ByteArray = imports.byteArray; 5 | 6 | var Application = GObject.registerClass({ 7 | GTypeName: 'Gtk4PortalTestApplication', 8 | }, class Application extends Gtk.Application { 9 | _init(params) { 10 | super._init(params); 11 | 12 | this.add_main_option('replace', 0, 0, 0, 'Replace the running instance', null); 13 | 14 | let action = new Gio.SimpleAction({ name: 'ack' }); 15 | action.connect('activate', () => this._window.ack()); 16 | this.add_action(action); 17 | 18 | action = new Gio.SimpleAction({ name: 'restart' }); 19 | action.connect('activate', () => this.restart()); 20 | this.add_action(action); 21 | 22 | action = new Gio.SimpleAction({ name: 'quit' }); 23 | action.connect('activate', () => this.quit()); 24 | this.add_action(action); 25 | } 26 | 27 | vfunc_activate() { 28 | super.vfunc_activate(); 29 | 30 | this._window.present(); 31 | } 32 | 33 | vfunc_startup() { 34 | super.vfunc_startup(); 35 | 36 | if (!this._window) 37 | this._window = new PortalTestWindow(this); 38 | } 39 | 40 | restart() { 41 | const bus = this.get_dbus_connection(); 42 | 43 | const s2ay = value => { 44 | let bytes; 45 | if (typeof value === 'string') { 46 | let byteArray = ByteArray.fromString(value); 47 | if (byteArray[byteArray.length - 1] !== 0) 48 | byteArray = Uint8Array.of(...byteArray, 0); 49 | bytes = ByteArray.toGBytes(byteArray); 50 | } else { 51 | bytes = new GLib.Bytes(value); 52 | } 53 | return GLib.Variant.new_from_bytes(new GLib.VariantType('ay'), 54 | bytes, true); 55 | }; 56 | 57 | bus.call( 58 | 'org.freedesktop.portal.Flatpak', 59 | '/org/freedesktop/portal/Flatpak', 60 | 'org.freedesktop.portal.Flatpak', 61 | 'Spawn', GLib.Variant.new_tuple([ 62 | s2ay('/'), 63 | GLib.Variant.new_array(new GLib.VariantType('ay'), [ 64 | s2ay('org.gnome.PortalTest.Gtk4'), 65 | s2ay('--replace'), 66 | ]), 67 | GLib.Variant.new_array(new GLib.VariantType('{uh}'), []), 68 | GLib.Variant.new_array(new GLib.VariantType('{ss}'), []), 69 | GLib.Variant.new_uint32(2), 70 | GLib.Variant.new_array(new GLib.VariantType('{sv}'), []), 71 | ]), 72 | new GLib.VariantType('(u)'), 73 | 0, -1, null, 74 | (connection, result) => { 75 | try { 76 | const res = bus.call_finish(result); 77 | log(`Restarted with pid ${res.deepUnpack()}`); 78 | } catch(e) { 79 | logError(e); 80 | return; 81 | } 82 | }); 83 | } 84 | }); 85 | -------------------------------------------------------------------------------- /portal-test/gtk4/main.js: -------------------------------------------------------------------------------- 1 | 2 | pkg.initGettext(); 3 | pkg.initFormat(); 4 | pkg.require({ 5 | 'GdkPixbuf': '2.0', 6 | 'Gio': '2.0', 7 | 'Gst': '1.0', 8 | 'Gtk': '4.0', 9 | 'Xdp': '1.0', 10 | 'XdpGtk4': '1.0', 11 | }); 12 | 13 | const { Gdk, Gio, GLib, Gst, Gtk } = imports.gi; 14 | 15 | const { Application } = imports.application; 16 | 17 | function stopRunningInstance() { 18 | const bus = Gio.DBus.session; 19 | 20 | const mainloop = GLib.MainLoop.new(null, false); 21 | 22 | const watchId = bus.watch_name( 23 | 'org.gnome.PortalTest.Gtk4', 24 | 0, 25 | (bus, name, owner) => { 26 | log(`Name ${name} owned by ${owner}`); 27 | }, 28 | (bus, name) => { 29 | log(`Name ${name} unowned`); 30 | mainloop.quit(); 31 | }); 32 | 33 | try { 34 | bus.call_sync( 35 | 'org.gnome.PortalTest.Gtk4', 36 | '/org/gnome/PortalTest/Gtk4', 37 | 'org.gtk.Actions', 38 | 'Activate', GLib.Variant.new_tuple([ 39 | GLib.Variant.new_string('quit'), 40 | new GLib.Variant('av', []), 41 | new GLib.Variant('a{sv}', {}), 42 | ]), 43 | null, 44 | Gio.DBusCallFlags.NONE, 45 | -1, null); 46 | } catch(e) { 47 | logError(e); 48 | } 49 | 50 | mainloop.run(); 51 | 52 | bus.unwatch_name(watchId); 53 | } 54 | 55 | function main(argv) { 56 | Gst.init(null); 57 | 58 | if (argv.indexOf('--replace') !== -1) 59 | stopRunningInstance(); 60 | 61 | const application = new Application({ 62 | application_id: 'org.gnome.PortalTest.Gtk4', 63 | flags: Gio.ApplicationFlags.FLAGS_NONE, 64 | }); 65 | 66 | return application.run(argv); 67 | } 68 | -------------------------------------------------------------------------------- /portal-test/gtk4/meson.build: -------------------------------------------------------------------------------- 1 | 2 | if not introspection 3 | error('The GTK4 test portal requires introspection') 4 | endif 5 | 6 | gst_dep = dependency('gstreamer-audio-1.0') 7 | 8 | package_name = 'portal-test-gtk4' 9 | pkgdatadir = get_option('datadir') / package_name 10 | 11 | data_resouces = gnome.compile_resources( 12 | 'org.gnome.PortalTest.Gtk4.data', 13 | 'org.gnome.PortalTest.Gtk4.data.gresource.xml', 14 | gresource_bundle: true, 15 | install: true, 16 | install_dir: pkgdatadir, 17 | ) 18 | 19 | js_resouces = gnome.compile_resources( 20 | 'org.gnome.PortalTest.Gtk4.src', 21 | 'org.gnome.PortalTest.Gtk4.src.gresource.xml', 22 | gresource_bundle: true, 23 | install: true, 24 | install_dir: pkgdatadir, 25 | ) 26 | 27 | bin_conf = configuration_data() 28 | bin_conf.set('GJS', find_program('gjs').full_path()) 29 | bin_conf.set('PACKAGE_NAME', package_name) 30 | bin_conf.set('PACKAGE_VERSION', '1.0.0') 31 | bin_conf.set('prefix', get_option('prefix')) 32 | bin_conf.set('libdir', get_option('prefix') / get_option('libdir')) 33 | bin_conf.set('datadir', get_option('prefix') / get_option('datadir')) 34 | 35 | portal_test_gtk4 = configure_file( 36 | input: 'org.gnome.PortalTest.Gtk4.in', 37 | output: 'org.gnome.PortalTest.Gtk4', 38 | configuration: bin_conf, 39 | ) 40 | install_data(portal_test_gtk4, install_mode: 'rwxr-xr-x', install_dir: get_option('bindir')) 41 | install_data('test.txt', install_dir: 'share/org.gnome.PortalTest.Gtk4') 42 | install_data('org.gnome.PortalTest.Gtk4.desktop', install_dir: 'share/applications') 43 | install_data('org.gnome.PortalTest.Gtk4.service', install_dir: 'share/dbus-1/services') 44 | 45 | executable('portal-linking-test-gtk4', 46 | [ 'portal-linking-test.c' ], 47 | include_directories: [libportal_inc], 48 | dependencies: [libportal_gtk4_dep], 49 | ) 50 | -------------------------------------------------------------------------------- /portal-test/gtk4/org.gnome.PortalTest.Gtk4.data.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | window.ui 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /portal-test/gtk4/org.gnome.PortalTest.Gtk4.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Name=Portal test (GTK4) 3 | Exec=org.gnome.PortalTest.Gtk4 4 | Type=Application 5 | DBusActivatable=true 6 | -------------------------------------------------------------------------------- /portal-test/gtk4/org.gnome.PortalTest.Gtk4.in: -------------------------------------------------------------------------------- 1 | #!@GJS@ 2 | imports.package.init({ 3 | name: "@PACKAGE_NAME@", 4 | version: "@PACKAGE_VERSION@", 5 | prefix: "@prefix@", 6 | libdir: "@libdir@", 7 | datadir: "@datadir@", 8 | }); 9 | imports.package.run(imports.main); 10 | -------------------------------------------------------------------------------- /portal-test/gtk4/org.gnome.PortalTest.Gtk4.service: -------------------------------------------------------------------------------- 1 | [D-BUS Service] 2 | Name=org.gnome.PortalTest.Gtk4 3 | Exec=org.gnome.PortalTest.Gtk4 4 | -------------------------------------------------------------------------------- /portal-test/gtk4/org.gnome.PortalTest.Gtk4.src.gresource.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | application.js 5 | main.js 6 | window.js 7 | 8 | 9 | -------------------------------------------------------------------------------- /portal-test/gtk4/portal-linking-test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int 4 | main (int argc, char **argv) 5 | { 6 | XdpPortal *portal; 7 | 8 | portal = xdp_portal_new (); 9 | (void) xdp_portal_is_camera_present (portal); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /portal-test/gtk4/test.txt: -------------------------------------------------------------------------------- 1 | Like a trash can fire in a prison cell \\ 2 | like a search light in the parking lot of hell 3 | -------------------------------------------------------------------------------- /portal-test/meson.build: -------------------------------------------------------------------------------- 1 | foreach backend : enabled_backends 2 | subdir(backend) 3 | endforeach 4 | -------------------------------------------------------------------------------- /portal-test/qt5/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "portal-test-qt.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | 10 | PortalTestQt *portalTest = new PortalTestQt(nullptr); 11 | portalTest->show(); 12 | 13 | return a.exec(); 14 | } 15 | -------------------------------------------------------------------------------- /portal-test/qt5/meson.build: -------------------------------------------------------------------------------- 1 | 2 | add_languages('cpp', required : true, native : false) 3 | 4 | src = [ 5 | 'main.cpp', 6 | 'portal-test-qt.h', 7 | 'portal-test-qt.cpp', 8 | ] 9 | 10 | prep = qt5.preprocess( 11 | moc_headers : 'portal-test-qt.h', 12 | moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'], 13 | ui_files : 'portal-test-qt.ui', 14 | dependencies: libportal_qt5_dep, 15 | ) 16 | 17 | executable('portal-test-qt5', 18 | [src, prep], 19 | include_directories: [top_inc, libportal_inc], 20 | dependencies: [libportal_qt5_dep], 21 | cpp_args : '-std=c++11', 22 | install : true, 23 | ) 24 | -------------------------------------------------------------------------------- /portal-test/qt5/portal-test-qt.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "portal-test-qt.h" 3 | #include "ui_portal-test-qt.h" 4 | 5 | #include 6 | 7 | PortalTestQt::PortalTestQt(QWidget *parent, Qt::WindowFlags f) 8 | : QMainWindow(parent, f) 9 | , m_mainWindow(new Ui_PortalTestQt) 10 | , m_portal(xdp_portal_new()) 11 | { 12 | m_mainWindow->setupUi(this); 13 | 14 | connect(m_mainWindow->openFileButton, &QPushButton::clicked, [=] (G_GNUC_UNUSED bool clicked) { 15 | XdpParent *parent; 16 | XdpOpenFileFlags flags = XDP_OPEN_FILE_FLAG_NONE; 17 | 18 | parent = xdp_parent_new_qt(windowHandle()); 19 | xdp_portal_open_file (m_portal, parent, "Portal Test Qt", nullptr /*filters*/, nullptr /*current_filters*/, 20 | nullptr /*choices*/, flags, nullptr /*cancellable*/, openedFile, this); 21 | xdp_parent_free (parent); 22 | }); 23 | } 24 | 25 | PortalTestQt::~PortalTestQt() 26 | { 27 | delete m_mainWindow; 28 | g_object_unref( m_portal); 29 | } 30 | 31 | void PortalTestQt::updateLastOpenedFile(const QString &file) 32 | { 33 | if (!file.isEmpty()) { 34 | m_mainWindow->openedFileLabel->setText(QStringLiteral("Opened file: %1").arg(file)); 35 | } else { 36 | m_mainWindow->openedFileLabel->setText(QStringLiteral("Failed to open a file!!!")); 37 | } 38 | } 39 | 40 | void PortalTestQt::openedFile(GObject *object, GAsyncResult *result, gpointer data) 41 | { 42 | Q_UNUSED(data); 43 | XdpPortal *portal = XDP_PORTAL (object); 44 | PortalTestQt *win = static_cast(data); 45 | g_autoptr(GError) error = nullptr; 46 | g_autoptr(GVariant) ret = nullptr; 47 | 48 | ret = xdp_portal_open_file_finish(portal, result, &error); 49 | 50 | if (ret) { 51 | const char **uris; 52 | if (g_variant_lookup(ret, "uris", "^a&s", &uris)) { 53 | win->updateLastOpenedFile(uris[0]); 54 | } 55 | } else { 56 | win->updateLastOpenedFile(QString()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /portal-test/qt5/portal-test-qt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #undef signals 6 | #include "libportal/portal-qt5.h" 7 | #define signals Q_SIGNALS 8 | 9 | class Ui_PortalTestQt; 10 | 11 | class PortalTestQt : public QMainWindow 12 | { 13 | Q_OBJECT 14 | public: 15 | PortalTestQt(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); 16 | ~PortalTestQt(); 17 | 18 | void updateLastOpenedFile(const QString &file); 19 | private: 20 | static void openedFile(GObject *object, GAsyncResult *result, gpointer data); 21 | 22 | Ui_PortalTestQt *m_mainWindow; 23 | XdpPortal *m_portal; 24 | }; 25 | -------------------------------------------------------------------------------- /portal-test/qt5/portal-test-qt.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PortalTestQt 4 | 5 | 6 | 7 | 0 8 | 0 9 | 355 10 | 100 11 | 12 | 13 | 14 | Portal Test Qt 15 | 16 | 17 | 18 | 19 | 20 | 21 | Open File... 22 | 23 | 24 | 25 | 26 | 27 | 28 | No file opened!! 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /portal-test/qt6/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | 4 | #include "portal-test-qt.h" 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | QApplication a(argc, argv); 9 | 10 | PortalTestQt *portalTest = new PortalTestQt(nullptr); 11 | portalTest->show(); 12 | 13 | return a.exec(); 14 | } 15 | -------------------------------------------------------------------------------- /portal-test/qt6/meson.build: -------------------------------------------------------------------------------- 1 | 2 | add_languages('cpp', required : true, native : false) 3 | 4 | src = [ 5 | 'main.cpp', 6 | 'portal-test-qt.h', 7 | 'portal-test-qt.cpp', 8 | ] 9 | 10 | prep = qt6.preprocess( 11 | moc_headers : 'portal-test-qt.h', 12 | moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'], 13 | ui_files : 'portal-test-qt.ui', 14 | dependencies: libportal_qt6_dep, 15 | ) 16 | 17 | executable('portal-test-qt6', 18 | [src, prep], 19 | include_directories: [top_inc, libportal_inc], 20 | dependencies: [libportal_qt6_dep], 21 | cpp_args : '-std=c++17', 22 | install : true, 23 | ) 24 | -------------------------------------------------------------------------------- /portal-test/qt6/portal-test-qt.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "portal-test-qt.h" 3 | #include "ui_portal-test-qt.h" 4 | 5 | #include 6 | 7 | PortalTestQt::PortalTestQt(QWidget *parent, Qt::WindowFlags f) 8 | : QMainWindow(parent, f) 9 | , m_mainWindow(new Ui_PortalTestQt) 10 | , m_portal(xdp_portal_new()) 11 | { 12 | m_mainWindow->setupUi(this); 13 | 14 | connect(m_mainWindow->openFileButton, &QPushButton::clicked, [=] (G_GNUC_UNUSED bool clicked) { 15 | XdpParent *parent; 16 | XdpOpenFileFlags flags = XDP_OPEN_FILE_FLAG_NONE; 17 | 18 | parent = xdp_parent_new_qt(windowHandle()); 19 | xdp_portal_open_file (m_portal, parent, "Portal Test Qt", nullptr /*filters*/, nullptr /*current_filters*/, 20 | nullptr /*choices*/, flags, nullptr /*cancellable*/, openedFile, this); 21 | xdp_parent_free (parent); 22 | }); 23 | } 24 | 25 | PortalTestQt::~PortalTestQt() 26 | { 27 | delete m_mainWindow; 28 | g_object_unref( m_portal); 29 | } 30 | 31 | void PortalTestQt::updateLastOpenedFile(const QString &file) 32 | { 33 | if (!file.isEmpty()) { 34 | m_mainWindow->openedFileLabel->setText(QStringLiteral("Opened file: %1").arg(file)); 35 | } else { 36 | m_mainWindow->openedFileLabel->setText(QStringLiteral("Failed to open a file!!!")); 37 | } 38 | } 39 | 40 | void PortalTestQt::openedFile(GObject *object, GAsyncResult *result, gpointer data) 41 | { 42 | Q_UNUSED(data); 43 | XdpPortal *portal = XDP_PORTAL (object); 44 | PortalTestQt *win = static_cast(data); 45 | g_autoptr(GError) error = nullptr; 46 | g_autoptr(GVariant) ret = nullptr; 47 | 48 | ret = xdp_portal_open_file_finish(portal, result, &error); 49 | 50 | if (ret) { 51 | const char **uris; 52 | if (g_variant_lookup(ret, "uris", "^a&s", &uris)) { 53 | win->updateLastOpenedFile(uris[0]); 54 | } 55 | } else { 56 | win->updateLastOpenedFile(QString()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /portal-test/qt6/portal-test-qt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #undef signals 6 | #include "libportal/portal-qt6.h" 7 | #define signals Q_SIGNALS 8 | 9 | class Ui_PortalTestQt; 10 | 11 | class PortalTestQt : public QMainWindow 12 | { 13 | Q_OBJECT 14 | public: 15 | PortalTestQt(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); 16 | ~PortalTestQt(); 17 | 18 | void updateLastOpenedFile(const QString &file); 19 | private: 20 | static void openedFile(GObject *object, GAsyncResult *result, gpointer data); 21 | 22 | Ui_PortalTestQt *m_mainWindow; 23 | XdpPortal *m_portal; 24 | }; 25 | -------------------------------------------------------------------------------- /portal-test/qt6/portal-test-qt.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | PortalTestQt 4 | 5 | 6 | 7 | 0 8 | 0 9 | 355 10 | 100 11 | 12 | 13 | 14 | Portal Test Qt 15 | 16 | 17 | 18 | 19 | 20 | 21 | Open File... 22 | 23 | 24 | 25 | 26 | 27 | 28 | No file opened!! 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /subprojects/gi-docgen.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | directory=gi-docgen 3 | url=https://gitlab.gnome.org/GNOME/gi-docgen.git 4 | push-url=ssh://git@gitlab.gnome.org:GNOME/gi-docgen.git 5 | revision=main 6 | depth=1 7 | -------------------------------------------------------------------------------- /tests/gir-testenv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Wrapper to set up the right environment variables and start a nested 4 | # shell. Usage: 5 | # 6 | # $ ./tests/gir-testenv.sh 7 | # (nested shell) $ pytest 8 | # (nested shell) $ exit 9 | # 10 | # If you have meson 0.58 or later, you can instead do: 11 | # $ meson devenv -C builddir 12 | # (nested shell) $ cd ../tests 13 | # (nested shell) $ pytest 14 | # (nested shell) $ exit 15 | # 16 | 17 | builddir=$(find $PWD -name meson-logs -printf "%h" -quit) 18 | 19 | if [ -z "$builddir" ]; then 20 | echo "Unable to find meson builddir" 21 | exit 1 22 | fi 23 | 24 | echo "Using meson builddir: $builddir" 25 | 26 | export LD_LIBRARY_PATH="$builddir/libportal:$LD_LIBRARY_PATH" 27 | export GI_TYPELIB_PATH="$builddir/libportal:$GI_TYPELIB_PATH" 28 | 29 | echo "pytest must be run from within the tests/ directory" 30 | # Don't think this is portable, but oh well 31 | ${SHELL} 32 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | if 'qt5' in enabled_backends 2 | subdir('qt5') 3 | endif 4 | if 'qt6' in enabled_backends 5 | subdir('qt6') 6 | endif 7 | 8 | if meson.version().version_compare('>= 0.56.0') 9 | pytest = find_program('pytest-3', 'pytest', required: false) 10 | pymod = import('python') 11 | python = pymod.find_installation('python3', modules: ['dbus', 'dbusmock'], required: false) 12 | 13 | if pytest.found() and python.found() 14 | test_env = environment() 15 | test_env.set('LD_LIBRARY_PATH', meson.project_build_root() / 'libportal') 16 | test_env.set('GI_TYPELIB_PATH', meson.project_build_root() / 'libportal') 17 | 18 | test('pytest', 19 | pytest, 20 | args: ['--verbose', '--verbose', '--log-level=DEBUG'], 21 | env: test_env, 22 | workdir: meson.current_source_dir(), 23 | timeout: 180, 24 | ) 25 | endif 26 | endif 27 | -------------------------------------------------------------------------------- /tests/pyportaltest/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from typing import Any, Dict, List, Tuple 6 | 7 | import gi 8 | from gi.repository import GLib 9 | from dbus.mainloop.glib import DBusGMainLoop 10 | 11 | import dbus 12 | import dbusmock 13 | import fcntl 14 | import logging 15 | import os 16 | import pytest 17 | import subprocess 18 | 19 | logging.basicConfig(format="%(levelname)s | %(name)s: %(message)s", level=logging.DEBUG) 20 | logger = logging.getLogger("pyportaltest") 21 | 22 | DBusGMainLoop(set_as_default=True) 23 | 24 | # Uncomment this to have dbus-monitor listen on the normal session address 25 | # rather than the test DBus. This can be useful for cases where *something* 26 | # messes up and tests run against the wrong bus. 27 | # 28 | # session_dbus_address = os.environ["DBUS_SESSION_BUS_ADDRESS"] 29 | 30 | 31 | def start_dbus_monitor() -> "subprocess.Process": 32 | import subprocess 33 | 34 | env = os.environ.copy() 35 | try: 36 | env["DBUS_SESSION_BUS_ADDRESS"] = session_dbus_address 37 | except NameError: 38 | # See comment above 39 | pass 40 | 41 | argv = ["dbus-monitor", "--session"] 42 | mon = subprocess.Popen(argv, env=env) 43 | 44 | def stop_dbus_monitor(): 45 | mon.terminate() 46 | mon.wait() 47 | 48 | GLib.timeout_add(2000, stop_dbus_monitor) 49 | return mon 50 | 51 | 52 | class PortalTest(dbusmock.DBusTestCase): 53 | """ 54 | Parent class for portal tests. Subclass from this and name it after the 55 | portal, e.g. ``TestWallpaper``. 56 | 57 | .. attribute:: portal_interface 58 | 59 | The :class:`dbus.Interface` referring to our portal 60 | 61 | .. attribute:: properties_interface 62 | 63 | A convenience :class:`dbus.Interface` referring to the DBus Properties 64 | interface, call ``Get``, ``Set`` or ``GetAll`` on this interface to 65 | retrieve the matching property/properties. 66 | 67 | .. attribute:: mock_interface 68 | 69 | The DBusMock :class:`dbus.Interface` that controls our DBus 70 | appearance. 71 | 72 | """ 73 | 74 | @classmethod 75 | def setUpClass(cls): 76 | if cls.__name__ != "PortalTest": 77 | cls.PORTAL_NAME = cls.__name__.removeprefix("Test") 78 | cls.INTERFACE_NAME = f"org.freedesktop.portal.{cls.PORTAL_NAME}" 79 | os.environ["LIBPORTAL_TEST_SUITE"] = "1" 80 | 81 | try: 82 | dbusmock.mockobject.DBusMockObject.EmitSignalDetailed 83 | except AttributeError: 84 | pytest.skip("Updated version of dbusmock required") 85 | 86 | cls.__have_session_bus = False 87 | 88 | @classmethod 89 | def ensure_session_bus(cls): 90 | if not cls.__have_session_bus: 91 | cls.__have_session_bus = True 92 | cls.start_session_bus() 93 | 94 | def setUp(self): 95 | self.p_mock = None 96 | self._mainloop = None 97 | self.dbus_monitor = None 98 | 99 | def setup_daemon(self, params=None, extra_templates: List[Tuple[str, Dict]] = []): 100 | """ 101 | Start a DBusMock daemon in a separate process. 102 | 103 | If extra_templates is specified, it is a list of tuples with the 104 | portal name as first value and the param dict to be passed to that 105 | template as second value, e.g. ("ScreenCast", {...}). 106 | """ 107 | self.ensure_session_bus() 108 | self.p_mock, self.obj_portal = self.spawn_server_template( 109 | template=f"pyportaltest/templates/{self.PORTAL_NAME.lower()}.py", 110 | parameters=params, 111 | stdout=subprocess.PIPE, 112 | ) 113 | 114 | flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL) 115 | fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK) 116 | self.mock_interface = dbus.Interface(self.obj_portal, dbusmock.MOCK_IFACE) 117 | self.properties_interface = dbus.Interface( 118 | self.obj_portal, dbus.PROPERTIES_IFACE 119 | ) 120 | self.portal_interface = dbus.Interface(self.obj_portal, self.INTERFACE_NAME) 121 | 122 | for t, tparams in extra_templates: 123 | template = f"pyportaltest/templates/{t.lower()}.py" 124 | self.obj_portal.AddTemplate( 125 | template, 126 | dbus.Dictionary(tparams, signature="sv"), 127 | dbus_interface=dbusmock.MOCK_IFACE, 128 | ) 129 | 130 | self.dbus_monitor = start_dbus_monitor() 131 | 132 | def tearDown(self): 133 | if self.p_mock: 134 | if self.p_mock.stdout: 135 | out = (self.p_mock.stdout.read() or b"").decode("utf-8") 136 | if out: 137 | print(out) 138 | self.p_mock.stdout.close() 139 | self.p_mock.terminate() 140 | self.p_mock.wait() 141 | 142 | if self.dbus_monitor: 143 | self.dbus_monitor.terminate() 144 | self.dbus_monitor.wait() 145 | 146 | @property 147 | def mainloop(self): 148 | """ 149 | The mainloop for this test. This mainloop automatically quits after a 150 | fixed timeout, but only on the first run. That's usually enough for 151 | tests, if you need to call mainloop.run() repeatedly ensure that a 152 | timeout handler is set to ensure quick test case failure in case of 153 | error. 154 | """ 155 | if self._mainloop is None: 156 | 157 | def quit(): 158 | self._mainloop.quit() 159 | self._mainloop = None 160 | 161 | self._mainloop = GLib.MainLoop() 162 | GLib.timeout_add(2000, quit) 163 | 164 | return self._mainloop 165 | 166 | def assert_version_eq(self, version: int): 167 | """Assert the given version number is the one our portal exports""" 168 | interface_name = self.INTERFACE_NAME 169 | params = {} 170 | self.setup_daemon(params) 171 | assert self.properties_interface.Get(interface_name, "version") == version 172 | -------------------------------------------------------------------------------- /tests/pyportaltest/templates/__init__.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from dbusmock import DBusMockObject 6 | from typing import Dict, Any, NamedTuple, Optional 7 | from itertools import count 8 | from gi.repository import GLib 9 | 10 | import dbus 11 | import logging 12 | 13 | 14 | ASVType = Dict[str, Any] 15 | 16 | logging.basicConfig(format="%(levelname).1s|%(name)s: %(message)s", level=logging.DEBUG) 17 | logger = logging.getLogger("templates") 18 | 19 | 20 | class MockParams: 21 | """ 22 | Helper class for storing template parameters. The Mock object passed into 23 | ``load()`` is shared between all templates. This makes it easy to have 24 | per-template parameters by calling: 25 | 26 | >>> params = MockParams.get(mock, MAIN_IFACE) 27 | >>> params.version = 1 28 | 29 | and later, inside a DBus method: 30 | >>> params = MockParams.get(self, MAIN_IFACE) 31 | >>> return params.version 32 | """ 33 | 34 | @classmethod 35 | def get(cls, mock, interface_name): 36 | params = getattr(mock, "params", {}) 37 | try: 38 | return params[interface_name] 39 | except KeyError: 40 | c = cls() 41 | params[interface_name] = c 42 | mock.params = params 43 | return c 44 | 45 | 46 | class Response(NamedTuple): 47 | response: int 48 | results: ASVType 49 | 50 | 51 | class Request: 52 | _token_counter = count() 53 | 54 | def __init__( 55 | self, bus_name: dbus.service.BusName, sender: str, options: Optional[ASVType] 56 | ): 57 | options = options or {} 58 | sender_token = sender.removeprefix(":").replace(".", "_") 59 | handle_token = options.get("handle_token", next(self._token_counter)) 60 | self.sender = sender 61 | self.handle = ( 62 | f"/org/freedesktop/portal/desktop/request/{sender_token}/{handle_token}" 63 | ) 64 | self.mock = DBusMockObject( 65 | bus_name=bus_name, 66 | path=self.handle, 67 | interface="org.freedesktop.portal.Request", 68 | props={}, 69 | ) 70 | self.mock.AddMethod("", "Close", "", "", "self.RemoveObject(self.path)") 71 | logger.debug(f"Request created at {self.handle}") 72 | 73 | def respond(self, response: Response, delay: int = 0): 74 | def respond(): 75 | logger.debug(f"Request.Response on {self.handle}: {response}") 76 | self.mock.EmitSignalDetailed( 77 | "", 78 | "Response", 79 | "ua{sv}", 80 | [dbus.UInt32(response.response), response.results], 81 | details={"destination": self.sender}, 82 | ) 83 | 84 | if delay > 0: 85 | GLib.timeout_add(delay, respond) 86 | else: 87 | respond() 88 | 89 | 90 | class Session: 91 | _token_counter = count() 92 | 93 | def __init__( 94 | self, bus_name: dbus.service.BusName, sender: str, options: Optional[ASVType] 95 | ): 96 | options = options or {} 97 | sender_token = sender.removeprefix(":").replace(".", "_") 98 | handle_token = options.get("session_handle_token", next(self._token_counter)) 99 | self.sender = sender 100 | self.handle = ( 101 | f"/org/freedesktop/portal/desktop/session/{sender_token}/{handle_token}" 102 | ) 103 | self.mock = DBusMockObject( 104 | bus_name=bus_name, 105 | path=self.handle, 106 | interface="org.freedesktop.portal.Session", 107 | props={}, 108 | ) 109 | self.mock.AddMethod("", "Close", "", "", "self.RemoveObject(self.path)") 110 | logger.debug(f"Session created at {self.handle}") 111 | 112 | def close(self, details: ASVType, delay: int = 0): 113 | def respond(): 114 | logger.debug(f"Session.Closed on {self.handle}: {details}") 115 | self.mock.EmitSignalDetailed( 116 | "", "Closed", "a{sv}", [details], details={"destination": self.sender} 117 | ) 118 | 119 | if delay > 0: 120 | GLib.timeout_add(delay, respond) 121 | else: 122 | respond() 123 | -------------------------------------------------------------------------------- /tests/pyportaltest/templates/notification.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from pyportaltest.templates import Request, Response, ASVType, MockParams 6 | from typing import Dict, List, Tuple, Iterator 7 | 8 | import dbus 9 | import dbus.service 10 | import logging 11 | 12 | logger = logging.getLogger(f"templates.{__name__}") 13 | 14 | BUS_NAME = "org.freedesktop.portal.Desktop" 15 | MAIN_OBJ = "/org/freedesktop/portal/desktop" 16 | SYSTEM_BUS = False 17 | MAIN_IFACE = "org.freedesktop.portal.Notification" 18 | 19 | 20 | def load(mock, parameters): 21 | logger.debug(f"loading {MAIN_IFACE} template") 22 | 23 | params = MockParams.get(mock, MAIN_IFACE) 24 | params.delay = 500 25 | params.version = parameters.get("version", 2) 26 | params.response = parameters.get("response", 0) 27 | 28 | mock.AddProperties( 29 | MAIN_IFACE, 30 | dbus.Dictionary({"version": dbus.UInt32(params.version)}), 31 | ) 32 | 33 | 34 | @dbus.service.method( 35 | MAIN_IFACE, 36 | sender_keyword="sender", 37 | in_signature="sa{sv}", 38 | out_signature="", 39 | ) 40 | def AddNotification(self, id, notification, sender): 41 | try: 42 | logger.debug(f"AddNotification: {id}, {notification}") 43 | 44 | except Exception as e: 45 | logger.critical(e) 46 | -------------------------------------------------------------------------------- /tests/pyportaltest/templates/screencast.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from pyportaltest.templates import Request, Response, Session, ASVType, MockParams 6 | from typing import Dict, List, Tuple, Iterator 7 | from itertools import count 8 | 9 | import dbus 10 | import dbus.service 11 | import logging 12 | import socket 13 | 14 | logger = logging.getLogger(f"templates.{__name__}") 15 | 16 | BUS_NAME = "org.freedesktop.portal.Desktop" 17 | MAIN_OBJ = "/org/freedesktop/portal/desktop" 18 | SYSTEM_BUS = False 19 | MAIN_IFACE = "org.freedesktop.portal.ScreenCast" 20 | 21 | _restore_tokens = count() 22 | 23 | 24 | def load(mock, parameters): 25 | logger.debug(f"loading {MAIN_IFACE} template") 26 | 27 | params = MockParams.get(mock, MAIN_IFACE) 28 | params.delay = 500 29 | params.version = parameters.get("version", 4) 30 | params.response = parameters.get("response", 0) 31 | # streams returned in Start 32 | params.streams = parameters.get("streams", []) 33 | # persist_mode returned in Start 34 | params.persist_mode = parameters.get("persist-mode", 0) 35 | params.sessions: Dict[str, Session] = {} 36 | 37 | mock.AddProperties( 38 | MAIN_IFACE, 39 | dbus.Dictionary( 40 | { 41 | "version": dbus.UInt32(params.version), 42 | "AvailableSourceTypes": dbus.UInt32( 43 | parameters.get("source-types", 0b111) 44 | ), 45 | "AvailableCursorModes": dbus.UInt32( 46 | parameters.get("cursor-modes", 0b111) 47 | ), 48 | } 49 | ), 50 | ) 51 | 52 | 53 | @dbus.service.method( 54 | MAIN_IFACE, 55 | sender_keyword="sender", 56 | in_signature="a{sv}", 57 | out_signature="o", 58 | ) 59 | def CreateSession(self, options, sender): 60 | try: 61 | logger.debug(f"CreateSession: {options}") 62 | params = MockParams.get(self, MAIN_IFACE) 63 | request = Request(bus_name=self.bus_name, sender=sender, options=options) 64 | 65 | session = Session(bus_name=self.bus_name, sender=sender, options=options) 66 | params.sessions[session.handle] = session 67 | 68 | response = Response(params.response, {}) 69 | 70 | request.respond(response, delay=params.delay) 71 | 72 | return request.handle 73 | except Exception as e: 74 | logger.critical(e) 75 | 76 | 77 | @dbus.service.method( 78 | MAIN_IFACE, 79 | sender_keyword="sender", 80 | in_signature="oa{sv}", 81 | out_signature="o", 82 | ) 83 | def SelectSources(self, session_handle, options, sender): 84 | try: 85 | logger.debug(f"SelectSources: {session_handle} {options}") 86 | params = MockParams.get(self, MAIN_IFACE) 87 | request = Request(bus_name=self.bus_name, sender=sender, options=options) 88 | 89 | response = Response(params.response, {}) 90 | 91 | request.respond(response, delay=params.delay) 92 | 93 | return request.handle 94 | except Exception as e: 95 | logger.critical(e) 96 | 97 | 98 | @dbus.service.method( 99 | MAIN_IFACE, 100 | sender_keyword="sender", 101 | in_signature="osa{sv}", 102 | out_signature="o", 103 | ) 104 | def Start(self, session_handle, parent_window, options, sender): 105 | try: 106 | logger.debug(f"Start: {session_handle} {options}") 107 | params = MockParams.get(self, MAIN_IFACE) 108 | request = Request(bus_name=self.bus_name, sender=sender, options=options) 109 | 110 | results = { 111 | "streams": params.streams, 112 | } 113 | 114 | if params.version >= 4: 115 | results["persist_mode"] = dbus.UInt32(params.persist_mode) 116 | if params.persist_mode != 0: 117 | results["restore_token"] = f"restore_token{next(_restore_tokens)}" 118 | 119 | response = Response(params.response, results) 120 | 121 | request.respond(response, delay=params.delay) 122 | 123 | return request.handle 124 | except Exception as e: 125 | logger.critical(e) 126 | 127 | 128 | @dbus.service.method( 129 | MAIN_IFACE, 130 | sender_keyword="sender", 131 | in_signature="oa{sv}", 132 | out_signature="h", 133 | ) 134 | def OpenPipeWireRemote(self, session_handle, options, sender): 135 | try: 136 | logger.debug(f"OpenPipeWireRemote: {session_handle} {options}") 137 | 138 | # libportal doesn't care about the socket, so let's use something we 139 | # can easily check 140 | sockets = socket.socketpair() 141 | 142 | pw_socket = sockets[0] 143 | pw_socket.send(b"I AM GROO^WPIPEWIRE") 144 | 145 | fd = sockets[1] 146 | 147 | logger.debug(f"OpenPipeWireRemote with fd {fd.fileno()}") 148 | 149 | return dbus.types.UnixFd(fd) 150 | except Exception as e: 151 | logger.critical(e) 152 | -------------------------------------------------------------------------------- /tests/pyportaltest/templates/wallpaper.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from pyportaltest.templates import Request, Response, ASVType, MockParams 6 | from typing import Dict, List, Tuple, Iterator 7 | 8 | import dbus 9 | import dbus.service 10 | import logging 11 | 12 | logger = logging.getLogger(f"templates.{__name__}") 13 | 14 | BUS_NAME = "org.freedesktop.portal.Desktop" 15 | MAIN_OBJ = "/org/freedesktop/portal/desktop" 16 | SYSTEM_BUS = False 17 | MAIN_IFACE = "org.freedesktop.portal.Wallpaper" 18 | 19 | 20 | def load(mock, parameters): 21 | logger.debug(f"loading {MAIN_IFACE} template") 22 | 23 | params = MockParams.get(mock, MAIN_IFACE) 24 | params.delay = 500 25 | params.response = parameters.get("response", 0) 26 | 27 | mock.AddProperties( 28 | MAIN_IFACE, 29 | dbus.Dictionary({"version": dbus.UInt32(parameters.get("version", 1))}), 30 | ) 31 | 32 | 33 | @dbus.service.method( 34 | MAIN_IFACE, 35 | sender_keyword="sender", 36 | in_signature="ssa{sv}", 37 | out_signature="o", 38 | ) 39 | def SetWallpaperURI(self, parent_window, uri, options, sender): 40 | try: 41 | logger.debug(f"SetWallpaperURI: {parent_window}, {uri}, {options}") 42 | params = MockParams.get(self, MAIN_IFACE) 43 | request = Request(bus_name=self.bus_name, sender=sender, options=options) 44 | 45 | response = Response(params.response, {}) 46 | 47 | request.respond(response, delay=params.delay) 48 | 49 | return request.handle 50 | except Exception as e: 51 | logger.critical(e) 52 | -------------------------------------------------------------------------------- /tests/pyportaltest/test_wallpaper.py: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: LGPL-3.0-only 2 | # 3 | # This file is formatted with Python Black 4 | 5 | from . import PortalTest 6 | 7 | import gi 8 | import logging 9 | 10 | gi.require_version("Xdp", "1.0") 11 | from gi.repository import GLib, Xdp 12 | 13 | logger = logging.getLogger(__name__) 14 | 15 | 16 | class TestWallpaper(PortalTest): 17 | def test_version(self): 18 | self.assert_version_eq(1) 19 | 20 | def set_wallpaper( 21 | self, uri_to_set: str, set_on: Xdp.WallpaperFlags, show_preview: bool 22 | ): 23 | params = {} 24 | self.setup_daemon(params) 25 | 26 | xdp = Xdp.Portal.new() 27 | assert xdp is not None 28 | 29 | flags = { 30 | "background": Xdp.WallpaperFlags.BACKGROUND, 31 | "lockscreen": Xdp.WallpaperFlags.LOCKSCREEN, 32 | "both": Xdp.WallpaperFlags.BACKGROUND | Xdp.WallpaperFlags.LOCKSCREEN, 33 | }[set_on] 34 | 35 | if show_preview: 36 | flags |= Xdp.WallpaperFlags.PREVIEW 37 | 38 | wallpaper_was_set = False 39 | 40 | def set_wallpaper_done(portal, task, data): 41 | nonlocal wallpaper_was_set 42 | wallpaper_was_set = portal.set_wallpaper_finish(task) 43 | self.mainloop.quit() 44 | 45 | xdp.set_wallpaper( 46 | parent=None, 47 | uri=uri_to_set, 48 | flags=flags, 49 | cancellable=None, 50 | callback=set_wallpaper_done, 51 | data=None, 52 | ) 53 | 54 | self.mainloop.run() 55 | 56 | method_calls = self.mock_interface.GetMethodCalls("SetWallpaperURI") 57 | assert len(method_calls) == 1 58 | timestamp, args = method_calls.pop(0) 59 | parent, uri, options = args 60 | assert uri == uri_to_set 61 | assert options["set-on"] == set_on 62 | assert options["show-preview"] == show_preview 63 | 64 | assert wallpaper_was_set 65 | 66 | def test_set_wallpaper_background(self): 67 | self.set_wallpaper("https://background.nopreview", "background", False) 68 | 69 | def test_set_wallpaper_background_preview(self): 70 | self.set_wallpaper("https://background.preview", "background", True) 71 | 72 | def test_set_wallpaper_lockscreen(self): 73 | self.set_wallpaper("https://lockscreen.nopreview", "lockscreen", False) 74 | 75 | def test_set_wallpaper_lockscreen_preview(self): 76 | self.set_wallpaper("https://lockscreen.preview", "lockscreen", True) 77 | 78 | def test_set_wallpaper_both(self): 79 | self.set_wallpaper("https://both.nopreview", "both", False) 80 | 81 | def test_set_wallpaper_both_preview(self): 82 | self.set_wallpaper("https://both.preview", "both", True) 83 | 84 | def test_set_wallpaper_cancel(self): 85 | params = {"response": 1} 86 | self.setup_daemon(params) 87 | 88 | xdp = Xdp.Portal.new() 89 | assert xdp is not None 90 | 91 | flags = Xdp.WallpaperFlags.BACKGROUND 92 | 93 | wallpaper_was_set = False 94 | 95 | def set_wallpaper_done(portal, task, data): 96 | nonlocal wallpaper_was_set 97 | try: 98 | wallpaper_was_set = portal.set_wallpaper_finish(task) 99 | except GLib.GError: 100 | pass 101 | self.mainloop.quit() 102 | 103 | xdp.set_wallpaper( 104 | parent=None, 105 | uri="https://ignored.anyway", 106 | flags=flags, 107 | cancellable=None, 108 | callback=set_wallpaper_done, 109 | data=None, 110 | ) 111 | 112 | self.mainloop.run() 113 | 114 | method_calls = self.mock_interface.GetMethodCalls("SetWallpaperURI") 115 | assert len(method_calls) == 1 116 | 117 | assert not wallpaper_was_set 118 | -------------------------------------------------------------------------------- /tests/qt5/meson.build: -------------------------------------------------------------------------------- 1 | add_languages('cpp', required : true, native : false) 2 | 3 | qt5_dep = dependency('qt5', modules: ['Core', 'Test']) 4 | 5 | src = [ 6 | 'test.cpp', 7 | 'test.h', 8 | ] 9 | 10 | prep = qt5.preprocess( 11 | moc_headers : 'test.h', 12 | moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'], 13 | dependencies: qt5_dep, 14 | ) 15 | 16 | exe = executable('qt5-test', 17 | [src, prep], 18 | include_directories: [top_inc, libportal_inc], 19 | dependencies: [qt5_dep, libportal_qt5_dep], 20 | cpp_args : '-std=c++11', 21 | ) 22 | 23 | test('Qt 5 unit test', exe) 24 | -------------------------------------------------------------------------------- /tests/qt5/test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Jan Grulich 3 | * Copyright (C) 2024 GNOME Foundation, Inc. 4 | * 5 | * This file is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, version 3.0 of the 8 | * License. 9 | * 10 | * This file is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program. If not, see . 17 | * 18 | * SPDX-License-Identifier: LGPL-3.0-only 19 | */ 20 | 21 | #include "test.h" 22 | 23 | #undef signals 24 | #include "portal-qt5.h" 25 | #define signals Q_SIGNALS 26 | 27 | #include 28 | #include 29 | 30 | void Test::testFileChooserPortal() 31 | { 32 | XdpQt::FileChooserFilterRule rule; 33 | rule.type = XdpQt::FileChooserFilterRuleType::Mimetype; 34 | rule.rule = QStringLiteral("image/jpeg"); 35 | 36 | XdpQt::FileChooserFilter filter; 37 | filter.label = QStringLiteral("Images"); 38 | filter.rules << rule; 39 | 40 | g_autoptr(GVariant) filterVar = XdpQt::filechooserFiltersToGVariant({filter}); 41 | const QString expectedFilterVarStr = QStringLiteral("[('Images', [(1, 'image/jpeg')])]"); 42 | g_autofree char *variantStr = g_variant_print(filterVar, false); 43 | const QString filterVarStr = variantStr; 44 | QCOMPARE(expectedFilterVarStr, filterVarStr); 45 | 46 | XdpQt::FileChooserFilterRule rule2; 47 | rule2.type = XdpQt::FileChooserFilterRuleType::Pattern; 48 | rule2.rule = QStringLiteral("*.png"); 49 | filter.rules << rule2; 50 | 51 | g_autoptr(GVariant) filterVar2 = XdpQt::filechooserFiltersToGVariant({filter}); 52 | const QString expectedFilterVarStr2 = "[('Images', [(1, 'image/jpeg'), (0, '*.png')])]"; 53 | g_autofree char *variantStr2 = g_variant_print(filterVar2, false); 54 | const QString filterVarStr2 = variantStr2; 55 | QCOMPARE(expectedFilterVarStr2, filterVarStr2); 56 | 57 | XdpQt::FileChooserChoice choice; 58 | choice.id = QStringLiteral("choice-id"); 59 | choice.label = QStringLiteral("choice-label"); 60 | choice.options.insert(QStringLiteral("option1-id"), QStringLiteral("option1-value")); 61 | choice.options.insert(QStringLiteral("option2-id"), QStringLiteral("option2-value")); 62 | choice.selected = QStringLiteral("option1-id"); 63 | 64 | g_autoptr(GVariant) choiceVar = XdpQt::filechooserChoicesToGVariant({choice}); 65 | const QString expectedChoiceVarStr = "[('choice-id', 'choice-label', [('option1-id', 'option1-value'), ('option2-id', 'option2-value')], 'option1-id')]"; 66 | g_autofree char *variantChoiceStr = g_variant_print(choiceVar, false); 67 | const QString choiceVarStr = variantChoiceStr; 68 | QCOMPARE(expectedChoiceVarStr, choiceVarStr); 69 | } 70 | 71 | void Test::testNotificationPortal() 72 | { 73 | XdpQt::NotificationButton button; 74 | button.label = QStringLiteral("Some label"); 75 | button.action = QStringLiteral("Some action"); 76 | 77 | XdpQt::Notification notification; 78 | notification.title = QStringLiteral("Test notification"); 79 | notification.body = QStringLiteral("Testing notification portal"); 80 | notification.icon = QStringLiteral("applications-development"); 81 | notification.buttons << button; 82 | 83 | g_autoptr(GVariant) notificationVar = XdpQt::notificationToGVariant(notification); 84 | const QString expectedNotificationVarStr = "{'title': <'Test notification'>, 'body': <'Testing notification portal'>, 'icon': <('themed', <['applications-development', 'applications-development-symbolic']>)>, 'buttons': <[{'label': <'Some label'>, 'action': <'Some action'>}]>}"; 85 | g_autofree char *variantStr = g_variant_print(notificationVar, false); 86 | const QString notificationStr = variantStr; 87 | QCOMPARE(expectedNotificationVarStr, notificationStr); 88 | } 89 | 90 | 91 | QTEST_GUILESS_MAIN(Test) 92 | -------------------------------------------------------------------------------- /tests/qt5/test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Jan Grulich 3 | * 4 | * This file is free software; you can redistribute it and/or modify it 5 | * under the terms of the GNU Lesser General Public License as 6 | * published by the Free Software Foundation, version 3.0 of the 7 | * License. 8 | * 9 | * This file is distributed in the hope that it will be useful, but 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Lesser General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this program. If not, see . 16 | * 17 | * SPDX-License-Identifier: LGPL-3.0-only 18 | */ 19 | 20 | #pragma once 21 | 22 | #include 23 | 24 | class Test : public QObject 25 | { 26 | Q_OBJECT 27 | private Q_SLOTS: 28 | void testFileChooserPortal(); 29 | void testNotificationPortal(); 30 | }; 31 | -------------------------------------------------------------------------------- /tests/qt6/meson.build: -------------------------------------------------------------------------------- 1 | add_languages('cpp', required : true, native : false) 2 | 3 | qt6_dep = dependency('qt6', modules: ['Core', 'Test']) 4 | 5 | src = [ 6 | 'test.cpp', 7 | 'test.h', 8 | ] 9 | 10 | prep = qt6.preprocess( 11 | moc_headers : 'test.h', 12 | moc_extra_arguments: ['-DMAKES_MY_MOC_HEADER_COMPILE'], 13 | dependencies: qt6_dep, 14 | ) 15 | 16 | exe = executable('qt6-test', 17 | [src, prep], 18 | include_directories: [top_inc, libportal_inc], 19 | dependencies: [qt6_dep, libportal_qt6_dep], 20 | cpp_args : '-std=c++17', 21 | ) 22 | 23 | test('Qt 6 unit test', exe) 24 | -------------------------------------------------------------------------------- /tests/qt6/test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Jan Grulich 3 | * Copyright (C) 2023, Neal Gompa 4 | * Copyright (C) 2024 GNOME Foundation, Inc. 5 | * 6 | * This file is free software; you can redistribute it and/or modify it 7 | * under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, version 3.0 of the 9 | * License. 10 | * 11 | * This file is distributed in the hope that it will be useful, but 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public 17 | * License along with this program. If not, see . 18 | * 19 | * SPDX-License-Identifier: LGPL-3.0-only 20 | */ 21 | 22 | #include "test.h" 23 | 24 | #undef signals 25 | #include "portal-qt6.h" 26 | #define signals Q_SIGNALS 27 | 28 | #include 29 | #include 30 | 31 | void Test::testFileChooserPortal() 32 | { 33 | XdpQt::FileChooserFilterRule rule; 34 | rule.type = XdpQt::FileChooserFilterRuleType::Mimetype; 35 | rule.rule = QStringLiteral("image/jpeg"); 36 | 37 | XdpQt::FileChooserFilter filter; 38 | filter.label = QStringLiteral("Images"); 39 | filter.rules << rule; 40 | 41 | g_autoptr(GVariant) filterVar = XdpQt::filechooserFiltersToGVariant({filter}); 42 | const QString expectedFilterVarStr = QStringLiteral("[('Images', [(1, 'image/jpeg')])]"); 43 | g_autofree char *variantFilterStr = g_variant_print(filterVar, false); 44 | const QString filterVarStr = variantFilterStr; 45 | QCOMPARE(expectedFilterVarStr, filterVarStr); 46 | 47 | XdpQt::FileChooserFilterRule rule2; 48 | rule2.type = XdpQt::FileChooserFilterRuleType::Pattern; 49 | rule2.rule = QStringLiteral("*.png"); 50 | filter.rules << rule2; 51 | 52 | g_autoptr(GVariant) filterVar2 = XdpQt::filechooserFiltersToGVariant({filter}); 53 | const QString expectedFilterVarStr2 = "[('Images', [(1, 'image/jpeg'), (0, '*.png')])]"; 54 | g_autofree char *variantFilterStr2 = g_variant_print(filterVar2, false); 55 | const QString filterVarStr2 = variantFilterStr2; 56 | QCOMPARE(expectedFilterVarStr2, filterVarStr2); 57 | 58 | XdpQt::FileChooserChoice choice; 59 | choice.id = QStringLiteral("choice-id"); 60 | choice.label = QStringLiteral("choice-label"); 61 | choice.options.insert(QStringLiteral("option1-id"), QStringLiteral("option1-value")); 62 | choice.options.insert(QStringLiteral("option2-id"), QStringLiteral("option2-value")); 63 | choice.selected = QStringLiteral("option1-id"); 64 | 65 | g_autoptr(GVariant) choiceVar = XdpQt::filechooserChoicesToGVariant({choice}); 66 | const QString expectedChoiceVarStr = "[('choice-id', 'choice-label', [('option1-id', 'option1-value'), ('option2-id', 'option2-value')], 'option1-id')]"; 67 | g_autofree char *variantChoiceStr = g_variant_print(choiceVar, false); 68 | const QString choiceVarStr = variantChoiceStr; 69 | QCOMPARE(expectedChoiceVarStr, choiceVarStr); 70 | } 71 | 72 | void Test::testNotificationPortal() 73 | { 74 | XdpQt::NotificationButton button; 75 | button.label = QStringLiteral("Some label"); 76 | button.action = QStringLiteral("Some action"); 77 | 78 | XdpQt::Notification notification; 79 | notification.title = QStringLiteral("Test notification"); 80 | notification.body = QStringLiteral("Testing notification portal"); 81 | notification.icon = QStringLiteral("applications-development"); 82 | notification.buttons << button; 83 | 84 | g_autoptr(GVariant) notificationVar = XdpQt::notificationToGVariant(notification); 85 | const QString expectedNotificationVarStr = "{'title': <'Test notification'>, 'body': <'Testing notification portal'>, 'icon': <('themed', <['applications-development', 'applications-development-symbolic']>)>, 'buttons': <[{'label': <'Some label'>, 'action': <'Some action'>}]>}"; 86 | g_autofree char *variantStr = g_variant_print(notificationVar, false); 87 | const QString notificationStr = variantStr; 88 | QCOMPARE(expectedNotificationVarStr, notificationStr); 89 | } 90 | 91 | 92 | QTEST_GUILESS_MAIN(Test) 93 | -------------------------------------------------------------------------------- /tests/qt6/test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2022, Jan Grulich 3 | * Copyright (C) 2023, Neal Gompa 4 | * 5 | * This file is free software; you can redistribute it and/or modify it 6 | * under the terms of the GNU Lesser General Public License as 7 | * published by the Free Software Foundation, version 3.0 of the 8 | * License. 9 | * 10 | * This file is distributed in the hope that it will be useful, but 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | * Lesser General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU Lesser General Public 16 | * License along with this program. If not, see . 17 | * 18 | * SPDX-License-Identifier: LGPL-3.0-only 19 | */ 20 | 21 | #pragma once 22 | 23 | #include 24 | 25 | class Test : public QObject 26 | { 27 | Q_OBJECT 28 | private Q_SLOTS: 29 | void testFileChooserPortal(); 30 | void testNotificationPortal(); 31 | }; 32 | --------------------------------------------------------------------------------