diff --git a/data/meson.build b/data/meson.build
index af8d30b0b..e3bc6a538 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -42,6 +42,10 @@ portal_sources = files(
'org.freedesktop.portal.Wallpaper.xml',
)
+portal_experimental_sources = files(
+ 'org.freedesktop.portal.experimental.Credential.xml',
+)
+
portal_host_sources = files(
'org.freedesktop.host.portal.Registry.xml',
)
@@ -73,10 +77,23 @@ portal_impl_sources = files(
'org.freedesktop.impl.portal.Wallpaper.xml',
)
+portal_impl_experimental_sources = files(
+ 'org.freedesktop.impl.portal.experimental.Credential.xml',
+)
+portal_handler_experimental_sources = files(
+ 'org.freedesktop.handler.portal.experimental.Credential.xml',
+)
+
background_monitor_sources = files(
'org.freedesktop.background.Monitor.xml',
)
-install_data([portal_sources, portal_host_sources, portal_impl_sources],
+install_data([
+ portal_sources,
+ portal_experimental_sources,
+ portal_host_sources,
+ portal_impl_sources,
+ portal_impl_experimental_sources,
+ ],
install_dir: datadir / 'dbus-1' / 'interfaces',
)
diff --git a/data/org.freedesktop.handler.portal.experimental.Credential.xml b/data/org.freedesktop.handler.portal.experimental.Credential.xml
new file mode 100644
index 000000000..be6acca30
--- /dev/null
+++ b/data/org.freedesktop.handler.portal.experimental.Credential.xml
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/org.freedesktop.impl.portal.experimental.Credential.xml b/data/org.freedesktop.impl.portal.experimental.Credential.xml
new file mode 100644
index 000000000..89a834e24
--- /dev/null
+++ b/data/org.freedesktop.impl.portal.experimental.Credential.xml
@@ -0,0 +1,455 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/org.freedesktop.portal.experimental.Credential.xml b/data/org.freedesktop.portal.experimental.Credential.xml
new file mode 100644
index 000000000..96f67440b
--- /dev/null
+++ b/data/org.freedesktop.portal.experimental.Credential.xml
@@ -0,0 +1,273 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/desktop-portal/credential.c b/desktop-portal/credential.c
new file mode 100644
index 000000000..89bad0cca
--- /dev/null
+++ b/desktop-portal/credential.c
@@ -0,0 +1,383 @@
+/*
+ * Copyright © 2025 Isaiah Inuwa
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors:
+ * Isaiah Inuwa
+ */
+
+#include "credential.h"
+
+#include
+
+#include
+
+#include "dex-aio.h"
+#include "gio/gio.h"
+#include "glib.h"
+#include "glibconfig.h"
+#include "xdp-app-info.h"
+#include "xdp-context.h"
+#include "xdp-experimental-dbus.h"
+#include "xdp-experimental-handler-dbus.h"
+#include "xdp-portal-config.h"
+#include "xdp-request-dex.h"
+#include "xdp-utils.h"
+
+static gboolean handle_create_credential (XdpDbusExperimentalCredential *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_parent_window,
+ const gchar *arg_origin,
+ const gchar *arg_type,
+ GVariant *arg_options);
+
+static gboolean handle_get_credential (XdpDbusExperimentalCredential *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_parent_window,
+ const gchar *arg_origin,
+ GVariant *arg_options);
+struct _XdpCredential
+{
+ XdpDbusExperimentalCredentialSkeleton parent_instance;
+
+ XdpContext *context;
+ XdpDbusExperimentalHandlerCredential *handler;
+};
+
+#define XDP_TYPE_CREDENTIAL (xdp_dbus_experimental_credential_get_type ())
+G_DECLARE_FINAL_TYPE (XdpCredential, xdp_credential, XDP, CREDENTIAL, XdpDbusExperimentalCredentialSkeleton)
+
+static void
+xdp_credential_iface_init (XdpDbusExperimentalCredentialIface *iface);
+
+G_DEFINE_FINAL_TYPE_WITH_CODE (
+ XdpCredential,
+ xdp_credential,
+ XDP_DBUS_EXPERIMENTAL_TYPE_CREDENTIAL_SKELETON,
+ G_IMPLEMENT_INTERFACE (XDP_DBUS_EXPERIMENTAL_TYPE_CREDENTIAL, xdp_credential_iface_init)
+ );
+
+static void xdp_credential_iface_init (XdpDbusExperimentalCredentialIface *iface)
+{
+ iface->handle_create_credential = handle_create_credential;
+ iface->handle_get_credential = handle_get_credential;
+}
+
+static void xdp_credential_dispose (GObject *object)
+{
+ XdpCredential *credential = XDP_CREDENTIAL (object);
+
+ g_clear_object (&credential->handler);
+
+ G_OBJECT_CLASS (xdp_credential_parent_class)->dispose (object);
+}
+
+static void xdp_credential_init (XdpCredential *credential) {}
+
+static void xdp_credential_class_init (XdpCredentialClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->dispose = xdp_credential_dispose;
+}
+
+static XdpCredential *
+xdp_credential_new(XdpContext *context, XdpDbusExperimentalHandlerCredential *handler)
+{
+ XdpCredential *credential;
+
+ credential = g_object_new(xdp_credential_get_type(), NULL);
+ credential->context = context;
+ credential->handler = g_object_ref(handler);
+
+ g_dbus_proxy_set_default_timeout (G_DBUS_PROXY (credential->handler), G_MAXINT);
+
+ xdp_dbus_experimental_credential_set_conditional_create (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+ xdp_dbus_experimental_credential_set_conditional_get (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+ xdp_dbus_experimental_credential_set_hybrid_transport (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE);
+ xdp_dbus_experimental_credential_set_passkey_platform_authenticator (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE);
+ xdp_dbus_experimental_credential_set_user_verifying_platform_authenticator (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+ xdp_dbus_experimental_credential_set_related_origins (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), TRUE);
+ xdp_dbus_experimental_credential_set_signal_all_accepted_credentials (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+ xdp_dbus_experimental_credential_set_signal_current_user_details (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+ xdp_dbus_experimental_credential_set_signal_unknown_credential (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), FALSE);
+
+ xdp_dbus_experimental_credential_set_version (
+ XDP_DBUS_EXPERIMENTAL_CREDENTIAL (credential), 1);
+
+ return credential;
+}
+
+const gchar *CREDENTIALSD_HANDLER_DBUS_NAME =
+ "xyz.iinuwa.credentialsd.Credentials";
+
+static XdpOptionKey create_credential_options[] = {
+ {"handle_token", G_VARIANT_TYPE_STRING, NULL},
+ {"origin", G_VARIANT_TYPE_STRING, NULL},
+ {"top_origin", G_VARIANT_TYPE_STRING, NULL},
+ {"type", G_VARIANT_TYPE_STRING, NULL},
+ {"public_key", G_VARIANT_TYPE_STRING, NULL},
+};
+
+/**
+ * create_credential_validate_options:
+ * @arg_options: (transfer none): options passed to the frontend.
+ * @error: (transfer none): pointer to an error pointer that will be populated on error.
+ * Returns: (transfer full): Filtered list of options to pass to the handler.
+ */
+static GVariant *
+create_credential_validate_options (GVariant *arg_options,
+ GError **error)
+{
+ g_auto (GVariantBuilder) options = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+ gboolean validated = xdp_filter_options (arg_options,
+ &options,
+ create_credential_options,
+ G_N_ELEMENTS (create_credential_options),
+ NULL,
+ error);
+ if (!validated)
+ return NULL;
+ else
+ return g_variant_ref_sink (g_variant_builder_end (&options));
+}
+
+static gboolean handle_create_credential (XdpDbusExperimentalCredential *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_parent_window,
+ const gchar *arg_origin,
+ const gchar *arg_type,
+ GVariant *arg_options)
+{
+ XdpCredential *credential = XDP_CREDENTIAL (object);
+ g_autoptr (XdpRequestDex) request = NULL;
+ g_autoptr (GVariant) options = NULL;
+ g_autoptr (GError) error = NULL;
+
+ XdpAppInfo *app_info = xdp_invocation_get_app_info (invocation);
+ const gchar *app_id = xdp_app_info_get_id (app_info);
+
+ options = create_credential_validate_options (arg_options, &error);
+ if (!options)
+ {
+ g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ request = dex_await_object (xdp_request_dex_new (
+ credential->context,
+ app_info,
+ G_DBUS_INTERFACE_SKELETON (object),
+ G_DBUS_PROXY (credential->handler),
+ options
+ ),
+ &error);
+ if (!request)
+ {
+ g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ xdp_dbus_experimental_credential_complete_create_credential (
+ object,
+ invocation,
+ xdp_request_dex_get_object_path (request));
+
+ {
+ g_autoptr (XdpDbusExperimentalHandlerCredentialCreateCredentialResult) result = NULL;
+ result = dex_await_boxed (xdp_dbus_experimental_handler_credential_call_create_credential_future (
+ credential->handler,
+ arg_parent_window,
+ arg_origin,
+ arg_type,
+ options,
+ app_id
+ ),
+ &error);
+
+ if (result) {
+ xdp_request_dex_emit_response (request,
+ result->response,
+ result->results);
+ } else {
+ g_dbus_error_strip_remote_error (error);
+ g_warning ("Handler call failed: %s (%d)", error->message, error->code);
+ xdp_request_dex_emit_response (request,
+ XDG_DESKTOP_PORTAL_RESPONSE_OTHER,
+ NULL);
+ }
+ }
+
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+static XdpOptionKey get_credential_options[] = {
+ {"handle_token", G_VARIANT_TYPE_STRING, NULL},
+ {"origin", G_VARIANT_TYPE_STRING, NULL},
+ {"top_origin", G_VARIANT_TYPE_STRING, NULL},
+ {"public_key", G_VARIANT_TYPE_STRING, NULL},
+};
+
+/**
+ * get_credential_validate_options:
+ * @arg_options: (transfer none): options passed to the frontend.
+ * @error: (transfer none): pointer to an error pointer that will be populated on error.
+ * Returns: (transfer full): Filtered list of options to pass to the handler.
+ */
+static GVariant *
+get_credential_validate_options (GVariant *arg_options,
+ GError **error)
+{
+ g_auto (GVariantBuilder) options = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+ gboolean validated = xdp_filter_options (arg_options,
+ &options,
+ get_credential_options,
+ G_N_ELEMENTS (get_credential_options),
+ NULL,
+ error);
+ if (!validated)
+ return NULL;
+ else
+ return g_variant_ref_sink (g_variant_builder_end (&options));
+}
+
+static gboolean handle_get_credential (XdpDbusExperimentalCredential *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_parent_window,
+ const gchar *arg_origin,
+ GVariant *arg_options)
+{
+ XdpCredential *credential = XDP_CREDENTIAL (object);
+ g_autoptr (XdpRequestDex) request = NULL;
+ g_autoptr (GVariant) options = NULL;
+ g_autoptr (GError) error = NULL;
+
+ XdpAppInfo *app_info = xdp_invocation_get_app_info (invocation);
+ const gchar *app_id = xdp_app_info_get_id (app_info);
+
+ options = get_credential_validate_options (arg_options, &error);
+ if (!options)
+ {
+ g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ request = dex_await_object (xdp_request_dex_new (
+ credential->context,
+ app_info,
+ G_DBUS_INTERFACE_SKELETON (object),
+ G_DBUS_PROXY (credential->handler),
+ options
+ ),
+ &error);
+ if (!request)
+ {
+ g_dbus_method_invocation_return_gerror (g_steal_pointer (&invocation), error);
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+ }
+
+ xdp_dbus_experimental_credential_complete_get_credential (
+ object,
+ invocation,
+ xdp_request_dex_get_object_path (request));
+
+ {
+ g_autoptr (XdpDbusExperimentalHandlerCredentialGetCredentialResult) result = NULL;
+ result = dex_await_boxed (xdp_dbus_experimental_handler_credential_call_get_credential_future (
+ credential->handler,
+ arg_parent_window,
+ arg_origin,
+ options,
+ app_id
+ ),
+ &error);
+
+ if (result) {
+ xdp_request_dex_emit_response (request,
+ result->response,
+ result->results);
+ } else {
+ g_dbus_error_strip_remote_error (error);
+ g_warning ("Handler call failed: %s (%d)", error->message, error->code);
+ xdp_request_dex_emit_response (request,
+ XDG_DESKTOP_PORTAL_RESPONSE_OTHER,
+ NULL);
+ }
+ }
+
+ return G_DBUS_METHOD_INVOCATION_HANDLED;
+}
+
+DexFuture *
+init_credential (gpointer user_data)
+{
+ g_info ("Initializing Credential Portal");
+
+ XdpContext *context = XDP_CONTEXT (user_data);
+ g_autoptr (XdpCredential) credential = NULL;
+ g_autoptr (XdpDbusExperimentalHandlerCredential) handler = NULL;
+ g_autoptr (GError) error = NULL;
+
+ GDBusConnection *connection = xdp_context_get_connection (context);
+ {
+ XdpPortalConfig *config = xdp_context_get_config (context);
+ XdpImplConfig *impl_config;
+
+ impl_config =
+ xdp_portal_config_find (config, CREDENTIAL_EXPERIMENTAL_DBUS_IMPL_IFACE);
+
+ if (impl_config == NULL) {
+ g_debug ("impl_config is NULL");
+ return dex_future_new_true ();
+ }
+
+ g_debug ("found impl");
+ }
+
+ g_debug ("creating handler proxy...");
+
+ handler = dex_await_object (xdp_dbus_experimental_handler_credential_proxy_new_future (
+ connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ CREDENTIALSD_HANDLER_DBUS_NAME,
+ DESKTOP_DBUS_PATH),
+ &error);
+
+ if (!handler)
+ {
+ g_warning ("Failed to create credential proxy: %s", error->message);
+ return dex_future_new_false ();
+ }
+ g_debug ("created handler proxy.");
+
+ credential = xdp_credential_new (context, g_steal_pointer (&handler));
+
+ xdp_context_take_and_export_portal (context,
+ G_DBUS_INTERFACE_SKELETON (g_steal_pointer (&credential)),
+ XDP_CONTEXT_EXPORT_FLAGS_RUN_IN_FIBER);
+
+ return dex_future_new_true ();
+}
diff --git a/desktop-portal/credential.h b/desktop-portal/credential.h
new file mode 100644
index 000000000..8beb09a93
--- /dev/null
+++ b/desktop-portal/credential.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2025 Isaiah Inuwa
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see .
+ *
+ * Authors:
+ * Isaiah Inuwa
+ */
+
+
+#pragma once
+
+#include
+
+DexFuture *
+init_credential (gpointer user_data);
+
diff --git a/desktop-portal/meson.build b/desktop-portal/meson.build
index 120001338..42c0b0dbf 100644
--- a/desktop-portal/meson.build
+++ b/desktop-portal/meson.build
@@ -13,6 +13,14 @@ portal_built_sources = gnome.gdbus_codegen(
docbook: 'portal',
extra_args: gdbus_codegen_extra_args,
)
+portal_experimental_built_sources = gnome.gdbus_codegen(
+ 'xdp-experimental-dbus',
+ sources: portal_experimental_sources,
+ interface_prefix: 'org.freedesktop.portal.experimental',
+ namespace: 'XdpDbusExperimental',
+ docbook: 'portal',
+ extra_args: gdbus_codegen_extra_args,
+)
host_built_sources = gnome.gdbus_codegen(
'xdp-host-dbus',
sources: portal_host_sources,
@@ -29,6 +37,22 @@ impl_built_sources = gnome.gdbus_codegen(
docbook: 'portal',
extra_args: gdbus_codegen_extra_args,
)
+impl_experimental_built_sources = gnome.gdbus_codegen(
+ 'xdp-impl-experimental-dbus',
+ sources: portal_impl_experimental_sources,
+ interface_prefix: 'org.freedesktop.impl.portal.experimental',
+ namespace: 'XdpDbusExperimentalImpl',
+ docbook: 'portal',
+ extra_args: gdbus_codegen_extra_args,
+)
+handler_experimental_built_sources = gnome.gdbus_codegen(
+ 'xdp-experimental-handler-dbus',
+ sources: portal_handler_experimental_sources,
+ interface_prefix: 'org.freedesktop.handler.portal.experimental',
+ namespace: 'XdpDbusExperimentalHandler',
+ docbook: 'portal',
+ extra_args: gdbus_codegen_extra_args,
+)
background_monitor_built_sources = gnome.gdbus_codegen(
'xdp-background-dbus',
sources: background_monitor_sources,
@@ -50,7 +74,7 @@ else
endif
xdp_method_info_built_sources = configure_file(
- command: [find_program('generate-method-info.py'), portal_sources],
+ command: [find_program('generate-method-info.py'), portal_sources, portal_experimental_sources],
capture: true,
output: 'xdp-method-info-generated.c',
)
@@ -62,6 +86,7 @@ xdg_desktop_portal_sources = files(
'background.c',
'camera.c',
'clipboard.c',
+ 'credential.c',
'dynamic-launcher.c',
'email.c',
'file-chooser.c',
@@ -105,8 +130,10 @@ xdg_desktop_portal_sources += [
xdp_utils_sources,
xdp_method_info_sources,
portal_built_sources,
+ portal_experimental_built_sources,
host_built_sources,
impl_built_sources,
+ handler_experimental_built_sources,
background_monitor_built_sources,
geoclue_built_sources,
]
diff --git a/desktop-portal/xdp-context.c b/desktop-portal/xdp-context.c
index 50b305de4..6f1665bfe 100644
--- a/desktop-portal/xdp-context.c
+++ b/desktop-portal/xdp-context.c
@@ -10,6 +10,7 @@
#include "background.h"
#include "camera.h"
#include "clipboard.h"
+#include "credential.h"
#include "dynamic-launcher.h"
#include "email.h"
#include "file-chooser.h"
@@ -484,6 +485,23 @@ xdp_context_register (XdpContext *context,
#endif
init_registry (context);
+ // Experimental feature flags
+ char *experimental_flag_env =
+ getenv ("XDG_DESKTOP_PORTAL_ENABLE_EXPERIMENTAL");
+ if (experimental_flag_env != NULL)
+ {
+ gchar **flags = g_strsplit (experimental_flag_env, ",", -1);
+ for (gint i = 0; flags[i] != NULL; i++)
+ {
+ gchar *flag = flags[i];
+ if (g_strcmp0 (flag, "credential") == 0)
+ {
+ g_debug ("Enabling experimental portal credential");
+ init_portal_in_fiber(context, init_credential);
+ }
+ }
+ }
+
return TRUE;
}
diff --git a/doc/api-reference.rst b/doc/api-reference.rst
index 0b192515f..bdb295763 100644
--- a/doc/api-reference.rst
+++ b/doc/api-reference.rst
@@ -65,3 +65,4 @@ replacement will be documented in :doc:`org.freedesktop.host.portal.Registry
doc-org.freedesktop.portal.Trash.rst
doc-org.freedesktop.portal.Usb.rst
doc-org.freedesktop.portal.Wallpaper.rst
+ doc-org.freedesktop.portal.experimental.Credential.rst
diff --git a/doc/fix-rst-dbus.py b/doc/fix-rst-dbus.py
index 731384679..ed39bee95 100755
--- a/doc/fix-rst-dbus.py
+++ b/doc/fix-rst-dbus.py
@@ -87,7 +87,15 @@ def split_sections(lines, output_prefix):
def adjust_title(lines):
title = lines[3].strip()
- if title.startswith("org.freedesktop.portal."):
+ if title.startswith("org.freedesktop.portal.experimental."):
+ adjusted_title = (
+ title.replace("org.freedesktop.portal.experimental.", "") + " 🧪"
+ )
+ elif title.startswith("org.freedesktop.impl.portal.experimental."):
+ adjusted_title = (
+ title.replace("org.freedesktop.impl.portal.experimental.", "") + " 🧪"
+ )
+ elif title.startswith("org.freedesktop.portal."):
adjusted_title = title.replace("org.freedesktop.portal.", "")
elif title.startswith("org.freedesktop.impl.portal"):
adjusted_title = title.replace("org.freedesktop.impl.portal.", "")
diff --git a/doc/impl-dbus-interfaces.rst b/doc/impl-dbus-interfaces.rst
index c78c645be..0133487d4 100644
--- a/doc/impl-dbus-interfaces.rst
+++ b/doc/impl-dbus-interfaces.rst
@@ -36,3 +36,4 @@ accessible to sandboxed applications.
doc-org.freedesktop.impl.portal.Settings.rst
doc-org.freedesktop.impl.portal.Usb.rst
doc-org.freedesktop.impl.portal.Wallpaper.rst
+ doc-org.freedesktop.impl.portal.experimental.Credential.rst
diff --git a/doc/meson.build b/doc/meson.build
index 4a94d984a..5a46b9c85 100644
--- a/doc/meson.build
+++ b/doc/meson.build
@@ -40,13 +40,13 @@ endif
if build_documentation
# Gather the XML files under data
all_interfaces_xml = []
- foreach i: portal_sources
+ foreach i: portal_sources + portal_experimental_sources
all_interfaces_xml += i
endforeach
foreach i: portal_host_sources
all_interfaces_xml += i
endforeach
- foreach i: portal_impl_sources
+ foreach i: portal_impl_sources + portal_impl_experimental_sources
all_interfaces_xml += i
endforeach
foreach i: background_monitor_sources
diff --git a/shared/xdp-types.h b/shared/xdp-types.h
index 8a5709709..b0dab411c 100644
--- a/shared/xdp-types.h
+++ b/shared/xdp-types.h
@@ -30,6 +30,9 @@ typedef struct _XdpDbusImplAccess XdpDbusImplAccess;
#define DESKTOP_DBUS_IFACE "org.freedesktop.portal"
#define DESKTOP_DBUS_IMPL_IFACE "org.freedesktop.impl.portal"
#define DESKTOP_DBUS_PATH "/org/freedesktop/portal/desktop"
+#define DESKTOP_EXPERIMENTAL_DBUS_IFACE DESKTOP_DBUS_IFACE ".experimental"
+#define DESKTOP_EXPERIMENTAL_DBUS_IMPL_IFACE \
+ DESKTOP_DBUS_IMPL_IFACE ".experimental"
#define ACCESS_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".Access"
@@ -52,6 +55,11 @@ typedef struct _XdpDbusImplAccess XdpDbusImplAccess;
#define CLIPBOARD_DBUS_IFACE DESKTOP_DBUS_IFACE ".Clipboard"
#define CLIPBOARD_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".Clipboard"
+#define CREDENTIAL_EXPERIMENTAL_DBUS_IFACE \
+ DESKTOP_EXPERIMENTAL_DBUS_IFACE ".Credential"
+#define CREDENTIAL_EXPERIMENTAL_DBUS_IMPL_IFACE \
+ DESKTOP_EXPERIMENTAL_DBUS_IMPL_IFACE ".Credential"
+
#define DYNAMIC_LAUNCHER_DBUS_IFACE DESKTOP_DBUS_IFACE ".DynamicLauncher"
#define DYNAMIC_LAUNCHER_DBUS_IMPL_IFACE DESKTOP_DBUS_IMPL_IFACE ".DynamicLauncher"