Merge branch 'portal-clients-fix' into 'master'

apply-access: un-gate portal clients after permission setup

Closes #941

See merge request pipewire/wireplumber!826
This commit is contained in:
Julian Bouzas 2026-05-07 11:26:48 +00:00
commit 2ec6b21328
2 changed files with 75 additions and 0 deletions

View file

@ -29,8 +29,33 @@ WP_DEFINE_LOCAL_LOG_TOPIC ("wp-permission-manager")
* a particular client.
*
* WpPermissionManager API.
*
* \gsignals
*
* \par client-properties-changed
* \parblock
* \code
* void
* client_properties_changed_callback (WpPermissionManager * self,
* WpClient *client,
* gpointer user_data)
* \endcode
* Emitted when the properties of an attached client change
*
* Parameters:
* - `client` - the client whose properties have changed
*
* Flags: G_SIGNAL_RUN_LAST
* \endparblock
*/
enum {
SIGNAL_CLIENT_PROPERTIES_CHANGED,
N_SIGNALS,
};
static guint32 signals[N_SIGNALS] = {0};
typedef struct _PermissionMatch PermissionMatch;
struct _PermissionMatch
{
@ -467,6 +492,18 @@ wp_permission_manager_class_init (WpPermissionManagerClass * klass)
wpobject_class->activate_execute_step =
wp_permission_manager_activate_execute_step;
wpobject_class->deactivate = wp_permission_manager_deactivate;
signals[SIGNAL_CLIENT_PROPERTIES_CHANGED] = g_signal_new (
"client-properties-changed", G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1,
WP_TYPE_CLIENT);
}
static void
on_client_properties_changed (WpClient * client, GParamSpec * param,
WpPermissionManager * self)
{
g_signal_emit (self, signals[SIGNAL_CLIENT_PROPERTIES_CHANGED], 0, client);
}
void
@ -476,6 +513,11 @@ wp_permission_manager_add_client (WpPermissionManager *self, WpClient *client)
g_ptr_array_add (self->clients, g_object_ref (client));
update_client_permissions (self, client);
g_signal_connect_object (client, "notify::properties",
G_CALLBACK (on_client_properties_changed), self, 0);
g_signal_emit (self, signals[SIGNAL_CLIENT_PROPERTIES_CHANGED], 0, client);
}
void
@ -486,6 +528,8 @@ wp_permission_manager_remove_client (WpPermissionManager *self,
g_ptr_array_remove_fast (self->clients, client);
update_client_permissions (self, client);
g_signal_handlers_disconnect_by_data (client, self);
}
/*!

View file

@ -48,6 +48,14 @@ function getCameraPermissions ()
return cached_camera_permissions
end
-- Advertise portal client gate support to the PW daemon.
-- This is set once on our own client at script load time
-- so PW's core_hello can detect that a capable session manager is
-- connected, regardless of which portal client is being processed.
Core.update_properties {
["pipewire.access.portal.gate-supported"] = "true"
}
-- The portal permission manager
portal_pm = PermissionManager ()
portal_pm:set_default_permissions (Perm.ALL)
@ -118,6 +126,29 @@ portal_pm:add_interest_match (
}
)
-- Handle portal client gating/ungating.
-- The PW daemon gates portal clients on fd handoff
-- (when an app connects via the stolen fd) by removing
-- PW_PERM_R from PW_ID_CORE and setting the property
-- pipewire.access.portal.gated to true. This makes
-- the client busy so the daemon stops reading from the
-- socket until permissions are set up properly.
--
-- two timing scenarios handled:
-- 1) gate is already set so ungate immediately.
-- 2) gate is set later (app connects after PermissionManager attached)
-- watch for the property change and ungate then.
portal_pm:connect ("client-properties-changed", function (pm, c)
local app_name = c:get_property ("application.name")
local gated = c:get_property ("pipewire.access.portal.gated")
if gated == "true" then
c:update_permissions { [0] = "rwx" }
log:info (c, string.format (
"Ungated portal client '%s' (via property change)",
app_name))
end
end)
-- Listen for changes and update permissions when that happens
if pps_plugin ~= nil then
pps_plugin:connect("changed", function (p, table, id, deleted, permissions)