diff --git a/.gitignore b/.gitignore index c8a95f4..145f1f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/xdg-desktop-portal-1.4.2.tar.xz +SOURCES/xdg-desktop-portal-1.6.0.tar.xz diff --git a/.xdg-desktop-portal.metadata b/.xdg-desktop-portal.metadata index c9e32d6..e91a12e 100644 --- a/.xdg-desktop-portal.metadata +++ b/.xdg-desktop-portal.metadata @@ -1 +1 @@ -33ee86c827ac570f92e766f1c79abb560e5ced1f SOURCES/xdg-desktop-portal-1.4.2.tar.xz +20875c7d4927bdfb7a446a4479eb3f100a177045 SOURCES/xdg-desktop-portal-1.6.0.tar.xz diff --git a/SOURCES/0001-Don-t-use-g_strv_equals.patch b/SOURCES/0001-Don-t-use-g_strv_equals.patch new file mode 100644 index 0000000..68350c1 --- /dev/null +++ b/SOURCES/0001-Don-t-use-g_strv_equals.patch @@ -0,0 +1,118 @@ +From 72fa3eca32d764f35b46642337c46ecc9b851177 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Jonas=20=C3=85dahl?= +Date: Mon, 25 May 2020 21:31:07 +0200 +Subject: [PATCH] Don't use g_strv_equals + +--- + tests/backend/email.c | 25 ++++++++++++++++++++++--- + tests/filechooser.c | 23 +++++++++++++++++++++-- + 2 files changed, 43 insertions(+), 5 deletions(-) + +diff --git a/tests/backend/email.c b/tests/backend/email.c +index 7d8844f..bab4ac6 100644 +--- a/tests/backend/email.c ++++ b/tests/backend/email.c +@@ -31,6 +31,25 @@ email_handle_free (EmailHandle *handle) + g_free (handle); + } + ++static gboolean ++strv_equal (const gchar * const *strv1, ++ const gchar * const *strv2) ++{ ++ g_return_val_if_fail (strv1 != NULL, FALSE); ++ g_return_val_if_fail (strv2 != NULL, FALSE); ++ ++ if (strv1 == strv2) ++ return TRUE; ++ ++ for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++) ++ { ++ if (!g_str_equal (*strv1, *strv2)) ++ return FALSE; ++ } ++ ++ return (*strv1 == NULL && *strv2 == NULL); ++} ++ + static gboolean + send_response (gpointer data) + { +@@ -70,7 +89,7 @@ send_response (gpointer data) + if (strv) + { + g_assert (addresses != NULL); +- g_assert_true (g_strv_equal ((const char * const *)strv, addresses)); ++ g_assert_true (strv_equal ((const char * const *)strv, addresses)); + g_strfreev (strv); + } + +@@ -78,7 +97,7 @@ send_response (gpointer data) + if (strv) + { + g_assert (addresses != NULL); +- g_assert_true (g_strv_equal ((const char * const *)strv, cc)); ++ g_assert_true (strv_equal ((const char * const *)strv, cc)); + g_strfreev (strv); + } + +@@ -86,7 +105,7 @@ send_response (gpointer data) + if (strv) + { + g_assert (addresses != NULL); +- g_assert_true (g_strv_equal ((const char * const *)strv, bcc)); ++ g_assert_true (strv_equal ((const char * const *)strv, bcc)); + g_strfreev (strv); + } + +diff --git a/tests/filechooser.c b/tests/filechooser.c +index a5f9b2c..a1a17cd 100644 +--- a/tests/filechooser.c ++++ b/tests/filechooser.c +@@ -12,6 +12,25 @@ extern char outdir[]; + + static int got_info; + ++static gboolean ++strv_equal (const gchar * const *strv1, ++ const gchar * const *strv2) ++{ ++ g_return_val_if_fail (strv1 != NULL, FALSE); ++ g_return_val_if_fail (strv2 != NULL, FALSE); ++ ++ if (strv1 == strv2) ++ return TRUE; ++ ++ for (; *strv1 != NULL && *strv2 != NULL; strv1++, strv2++) ++ { ++ if (!g_str_equal (*strv1, *strv2)) ++ return FALSE; ++ } ++ ++ return (*strv1 == NULL && *strv2 == NULL); ++} ++ + static void + open_file_cb (GObject *obj, + GAsyncResult *result, +@@ -41,7 +60,7 @@ open_file_cb (GObject *obj, + g_variant_lookup (ret, "uris", "^a&s", &uris); + expected_uris = g_key_file_get_string_list (keyfile, "result", "uris", NULL, NULL); + +- g_assert (g_strv_equal (uris, (const char * const *)expected_uris)); ++ g_assert (strv_equal (uris, (const char * const *)expected_uris)); + + expected_choices = g_key_file_get_string (keyfile, "result", "choices", NULL); + g_variant_lookup (ret, "choices", "@a(ss)", &choices); +@@ -670,7 +689,7 @@ save_file_cb (GObject *obj, + g_variant_lookup (ret, "uris", "^a&s", &uris); + expected = g_key_file_get_string_list (keyfile, "result", "uris", NULL, NULL); + +- g_assert (g_strv_equal (uris, (const char * const *)expected)); ++ g_assert (strv_equal (uris, (const char * const *)expected)); + } + else if (response == 1) + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); +-- +2.26.2 + diff --git a/SOURCES/0001-PipeWire-update-to-0.3-API.patch b/SOURCES/0001-PipeWire-update-to-0.3-API.patch new file mode 100644 index 0000000..c20b44d --- /dev/null +++ b/SOURCES/0001-PipeWire-update-to-0.3-API.patch @@ -0,0 +1,555 @@ +From 18dc92eac270a50fb40607602352efb4d3db8207 Mon Sep 17 00:00:00 2001 +From: Wim Taymans +Date: Tue, 14 Jan 2020 09:37:09 +0100 +Subject: [PATCH] PipeWire: update to 0.3 API + +(cherry picked from commit a38901e5e7f835efe7b7a06c55790c8c20bc91a2) +--- + configure.ac | 2 +- + src/camera.c | 24 ++++---- + src/pipewire.c | 141 +++++++++++++--------------------------------- + src/pipewire.h | 10 ++-- + src/screen-cast.c | 98 ++++++-------------------------- + 5 files changed, 72 insertions(+), 203 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 89902fa..62d7960 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -97,7 +97,7 @@ AC_ARG_ENABLE(pipewire, + [AS_HELP_STRING([--enable-pipewire],[Enable PipeWire support. Needed for screen cast portal])], + enable_pipewire=$enableval, enable_pipewire=yes) + if test x$enable_pipewire = xyes ; then +- PKG_CHECK_MODULES(PIPEWIRE, [libpipewire-0.2 >= 0.2.6]) ++ PKG_CHECK_MODULES(PIPEWIRE, [libpipewire-0.3 >= 0.2.90]) + AC_DEFINE([HAVE_PIPEWIRE],[1], [Define to enable PipeWire support]) + fi + AM_CONDITIONAL([HAVE_PIPEWIRE],[test "$enable_pipewire" = "yes"]) +diff --git a/src/camera.c b/src/camera.c +index c2b392c..20fe3aa 100644 +--- a/src/camera.c ++++ b/src/camera.c +@@ -141,7 +141,7 @@ open_pipewire_camera_remote (const char *app_id, + GError **error) + { + PipeWireRemote *remote; +- struct spa_dict_item permission_items[1]; ++ struct pw_permission permission_items[2]; + struct pw_properties *pipewire_properties; + + pipewire_properties = +@@ -158,12 +158,12 @@ open_pipewire_camera_remote (const char *app_id, + * Hide all existing and future nodes by default. PipeWire will use the + * permission store to set up permissions. + */ +- permission_items[0].key = PW_CORE_PROXY_PERMISSIONS_DEFAULT; +- permission_items[0].value = "---"; ++ permission_items[0] = PW_PERMISSION_INIT (PW_ID_CORE, PW_PERM_RWX); ++ permission_items[1] = PW_PERMISSION_INIT (PW_ID_ANY, 0); + +- pw_core_proxy_permissions (pw_remote_get_core_proxy (remote->remote), +- &SPA_DICT_INIT (permission_items, +- G_N_ELEMENTS (permission_items))); ++ pw_client_update_permissions (pw_core_get_client(remote->core), ++ G_N_ELEMENTS (permission_items), ++ permission_items); + + pipewire_remote_roundtrip (remote); + +@@ -219,7 +219,7 @@ handle_open_pipewire_remote (XdpCamera *object, + } + + out_fd_list = g_unix_fd_list_new (); +- fd = pw_remote_steal_fd (remote->remote); ++ fd = pw_core_steal_fd (remote->core); + fd_id = g_unix_fd_list_append (out_fd_list, fd, &error); + close (fd); + pipewire_remote_destroy (remote); +@@ -250,29 +250,28 @@ camera_iface_init (XdpCameraIface *iface) + static void + global_added_cb (PipeWireRemote *remote, + uint32_t id, +- uint32_t type, ++ const char *type, + const struct spa_dict *props, + gpointer user_data) + { + Camera *camera = user_data; +- struct pw_type *core_type = pw_core_get_type (remote->core); + const struct spa_dict_item *media_class; + const struct spa_dict_item *media_role; + +- if (type != core_type->node) ++ if (strcmp(type, PW_TYPE_INTERFACE_Node) != 0) + return; + + if (!props) + return; + +- media_class = spa_dict_lookup_item (props, "media.class"); ++ media_class = spa_dict_lookup_item (props, PW_KEY_MEDIA_CLASS); + if (!media_class) + return; + + if (g_strcmp0 (media_class->value, "Video/Source") != 0) + return; + +- media_role = spa_dict_lookup_item (props, "media.role"); ++ media_role = spa_dict_lookup_item (props, PW_KEY_MEDIA_ROLE); + if (!media_role) + return; + +@@ -342,6 +341,7 @@ create_pipewire_remote (Camera *camera, + } + + pipewire_properties = pw_properties_new ("pipewire.access.portal.is_portal", "true", ++ "portal.monitor", "Camera", + NULL); + camera->pipewire_remote = pipewire_remote_new_sync (pipewire_properties, + global_added_cb, +diff --git a/src/pipewire.c b/src/pipewire.c +index 793a378..162cd55 100644 +--- a/src/pipewire.c ++++ b/src/pipewire.c +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + + #include "pipewire.h" + +@@ -36,27 +37,25 @@ static gboolean is_pipewire_initialized = FALSE; + static void + registry_event_global (void *user_data, + uint32_t id, +- uint32_t parent_id, + uint32_t permissions, +- uint32_t type, ++ const char *type, + uint32_t version, + const struct spa_dict *props) + { + PipeWireRemote *remote = user_data; +- struct pw_type *core_type = pw_core_get_type (remote->core); + const struct spa_dict_item *factory_object_type; + PipeWireGlobal *global; + + global = g_new0 (PipeWireGlobal, 1); + *global = (PipeWireGlobal) { +- .parent_id = parent_id, ++ .parent_id = id, + }; + + g_hash_table_insert (remote->globals, GINT_TO_POINTER (id), global); + if (remote->global_added_cb) + remote->global_added_cb (remote, id, type, props, remote->user_data); + +- if (type != core_type->factory) ++ if (strcmp(type, PW_TYPE_INTERFACE_Factory) != 0) + return; + + factory_object_type = spa_dict_lookup_item (props, "factory.type.name"); +@@ -81,8 +80,8 @@ registry_event_global_remove (void *user_data, + g_hash_table_remove (remote->globals, GINT_TO_POINTER (id)); + } + +-static const struct pw_registry_proxy_events registry_events = { +- PW_VERSION_REGISTRY_PROXY_EVENTS, ++static const struct pw_registry_events registry_events = { ++ PW_VERSION_REGISTRY_EVENTS, + .global = registry_event_global, + .global_remove = registry_event_global_remove, + }; +@@ -90,7 +89,7 @@ static const struct pw_registry_proxy_events registry_events = { + void + pipewire_remote_roundtrip (PipeWireRemote *remote) + { +- pw_core_proxy_sync (remote->core_proxy, ++remote->sync_seq); ++ remote->sync_seq = pw_core_sync (remote->core, PW_ID_CORE, remote->sync_seq); + pw_main_loop_run (remote->loop); + } + +@@ -98,16 +97,13 @@ static gboolean + discover_node_factory_sync (PipeWireRemote *remote, + GError **error) + { +- struct pw_type *core_type = pw_core_get_type (remote->core); +- struct pw_registry_proxy *registry_proxy; ++ struct pw_registry *registry; + +- registry_proxy = pw_core_proxy_get_registry (remote->core_proxy, +- core_type->registry, +- PW_VERSION_REGISTRY, 0); +- pw_registry_proxy_add_listener (registry_proxy, +- &remote->registry_listener, +- ®istry_events, +- remote); ++ registry = pw_core_get_registry (remote->core, PW_VERSION_REGISTRY, 0); ++ pw_registry_add_listener (registry, ++ &remote->registry_listener, ++ ®istry_events, ++ remote); + + pipewire_remote_roundtrip (remote); + +@@ -122,59 +118,35 @@ discover_node_factory_sync (PipeWireRemote *remote, + } + + static void +-on_state_changed (void *user_data, +- enum pw_remote_state old, +- enum pw_remote_state state, +- const char *error) ++core_event_error (void *user_data, ++ uint32_t id, ++ int seq, ++ int res, ++ const char *message) + { + PipeWireRemote *remote = user_data; + +- switch (state) ++ if (id == PW_ID_CORE) + { +- case PW_REMOTE_STATE_ERROR: +- if (!remote->error) +- { +- g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "%s", error); +- } ++ g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED, ++ "%s", message); + pw_main_loop_quit (remote->loop); +- break; +- case PW_REMOTE_STATE_UNCONNECTED: +- if (!remote->error) +- { +- g_set_error (&remote->error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Disconnected"); +- } +- pw_main_loop_quit (remote->loop); +- break; +- case PW_REMOTE_STATE_CONNECTING: +- break; +- case PW_REMOTE_STATE_CONNECTED: +- pw_main_loop_quit (remote->loop); +- break; +- default: +- g_warning ("Unknown PipeWire state"); +- break; + } + } + +-static const struct pw_remote_events remote_events = { +- PW_VERSION_REMOTE_EVENTS, +- .state_changed = on_state_changed, +-}; +- + static void + core_event_done (void *user_data, +- uint32_t seq) ++ uint32_t id, int seq) + { + PipeWireRemote *remote = user_data; + +- if (remote->sync_seq == seq) ++ if (id == PW_ID_CORE && remote->sync_seq == seq) + pw_main_loop_quit (remote->loop); + } + +-static const struct pw_core_proxy_events core_events = { +- PW_VERSION_CORE_PROXY_EVENTS, ++static const struct pw_core_events core_events = { ++ PW_VERSION_CORE_EVENTS, ++ .error = core_event_error, + .done = core_event_done, + }; + +@@ -237,8 +209,8 @@ void + pipewire_remote_destroy (PipeWireRemote *remote) + { + g_clear_pointer (&remote->globals, g_hash_table_destroy); +- g_clear_pointer (&remote->remote, pw_remote_destroy); +- g_clear_pointer (&remote->core, pw_core_destroy); ++ g_clear_pointer (&remote->core, pw_core_disconnect); ++ g_clear_pointer (&remote->context, pw_context_destroy); + g_clear_pointer (&remote->loop, pw_main_loop_destroy); + g_clear_error (&remote->error); + +@@ -307,68 +279,31 @@ pipewire_remote_new_sync (struct pw_properties *pipewire_properties, + return NULL; + } + +- remote->core = pw_core_new (pw_main_loop_get_loop (remote->loop), NULL); +- if (!remote->core) ++ remote->context = pw_context_new (pw_main_loop_get_loop (remote->loop), NULL, 0); ++ if (!remote->context) + { + pipewire_remote_destroy (remote); + pw_properties_free (pipewire_properties); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Couldn't create PipeWire core"); ++ "Couldn't create PipeWire context"); + return NULL; + } + +- remote->remote = pw_remote_new (remote->core, pipewire_properties, 0); +- if (!remote->remote) ++ remote->core = pw_context_connect (remote->context, pipewire_properties, 0); ++ if (!remote->core) + { + pipewire_remote_destroy (remote); + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Couldn't create PipeWire remote"); ++ "Couldn't connect to PipeWire"); + return NULL; + } + + remote->globals = g_hash_table_new_full (NULL, NULL, NULL, g_free); + +- pw_remote_add_listener (remote->remote, +- &remote->remote_listener, +- &remote_events, +- remote); +- +- if (pw_remote_connect (remote->remote) != 0) +- { +- pipewire_remote_destroy (remote); +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Couldn't connect PipeWire remote"); +- return NULL; +- } +- +- pw_main_loop_run (remote->loop); +- +- switch (pw_remote_get_state (remote->remote, NULL)) +- { +- case PW_REMOTE_STATE_ERROR: +- case PW_REMOTE_STATE_UNCONNECTED: +- *error = g_steal_pointer (&remote->error); +- pipewire_remote_destroy (remote); +- return NULL; +- case PW_REMOTE_STATE_CONNECTING: +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "PipeWire loop stopped unexpectedly"); +- pipewire_remote_destroy (remote); +- return NULL; +- case PW_REMOTE_STATE_CONNECTED: +- break; +- default: +- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, +- "Unexpected PipeWire state"); +- pipewire_remote_destroy (remote); +- return NULL; +- } +- +- remote->core_proxy = pw_remote_get_core_proxy (remote->remote); +- pw_core_proxy_add_listener (remote->core_proxy, +- &remote->core_listener, +- &core_events, +- remote); ++ pw_core_add_listener (remote->core, ++ &remote->core_listener, ++ &core_events, ++ remote); + + if (!discover_node_factory_sync (remote, error)) + { +diff --git a/src/pipewire.h b/src/pipewire.h +index 0f1bf54..bf48d5e 100644 +--- a/src/pipewire.h ++++ b/src/pipewire.h +@@ -32,7 +32,7 @@ typedef struct _PipeWireGlobal + + typedef void (* PipeWireGlobalAddedCallback) (PipeWireRemote *remote, + uint32_t id, +- uint32_t type, ++ const char *type, + const struct spa_dict *props, + gpointer user_data); + +@@ -43,13 +43,11 @@ typedef void (* PipeWireGlobalRemovedCallback) (PipeWireRemote *remote, + struct _PipeWireRemote + { + struct pw_main_loop *loop; ++ struct pw_context *context; + struct pw_core *core; +- struct pw_remote *remote; +- struct spa_hook remote_listener; +- +- struct pw_core_proxy *core_proxy; + struct spa_hook core_listener; +- uint32_t sync_seq; ++ ++ int sync_seq; + + struct spa_hook registry_listener; + +diff --git a/src/screen-cast.c b/src/screen-cast.c +index 7881ddc..1677050 100644 +--- a/src/screen-cast.c ++++ b/src/screen-cast.c +@@ -31,10 +31,10 @@ + #include "xdp-impl-dbus.h" + #include "xdp-utils.h" + +-#define PERMISSION_ITEM(item_key, item_value) \ +- ((struct spa_dict_item) { \ +- .key = item_key, \ +- .value = item_value \ ++#define PERMISSION_ITEM(item_id, item_permissions) \ ++ ((struct pw_permission) { \ ++ .id = item_id, \ ++ .permissions = item_permissions \ + }) + + typedef struct _ScreenCast ScreenCast; +@@ -517,42 +517,9 @@ screen_cast_stream_get_pipewire_node_id (ScreenCastStream *stream) + return stream->id; + } + +-static void +-append_parent_permissions (PipeWireRemote *remote, +- GArray *permission_items, +- GList **string_stash, +- PipeWireGlobal *global, +- const char *permission) +-{ +- PipeWireGlobal *parent; +- char *parent_permission_value; +- +- if (global->parent_id == 0) +- return; +- +- parent = g_hash_table_lookup (remote->globals, GINT_TO_POINTER (global->parent_id)); +- +- if (parent->permission_set) +- return; +- parent->permission_set = TRUE; +- +- append_parent_permissions (remote, permission_items, string_stash, +- parent, permission); +- +- parent_permission_value = g_strdup_printf ("%u:%s", +- global->parent_id, +- permission); +- *string_stash = g_list_prepend (*string_stash, parent_permission_value); +- +- g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL, +- parent_permission_value)); +-} +- + static void + append_stream_permissions (PipeWireRemote *remote, + GArray *permission_items, +- GList **string_stash, + GList *streams) + { + GList *l; +@@ -561,21 +528,10 @@ append_stream_permissions (PipeWireRemote *remote, + { + ScreenCastStream *stream = l->data; + uint32_t stream_id; +- PipeWireGlobal *stream_global; +- char *stream_permission_value; + + stream_id = screen_cast_stream_get_pipewire_node_id (stream); +- stream_global = g_hash_table_lookup (remote->globals, +- GINT_TO_POINTER (stream_id)); +- +- append_parent_permissions (remote, permission_items, string_stash, +- stream_global, "r--"); +- +- stream_permission_value = g_strdup_printf ("%u:rwx", stream_id); +- *string_stash = g_list_prepend (*string_stash, stream_permission_value); + g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL, +- stream_permission_value)); ++ PERMISSION_ITEM (stream_id, PW_PERM_RWX)); + } + } + +@@ -587,9 +543,6 @@ open_pipewire_screen_cast_remote (const char *app_id, + struct pw_properties *pipewire_properties; + PipeWireRemote *remote; + g_autoptr(GArray) permission_items = NULL; +- char *node_factory_permission_string; +- GList *string_stash = NULL; +- struct spa_dict *permission_dict; + PipeWireGlobal *node_global; + + pipewire_properties = pw_properties_new ("pipewire.access.portal.app_id", app_id, +@@ -603,48 +556,31 @@ open_pipewire_screen_cast_remote (const char *app_id, + + permission_items = g_array_new (FALSE, TRUE, sizeof (struct spa_dict_item)); + +- /* +- * Hide all existing and future nodes (except the ones we explicitly list below. +- */ +- g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_EXISTING, +- "---")); +- g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_DEFAULT, +- "---")); +- + /* + * PipeWire:Interface:Core + * Needs rwx to be able create the sink node using the create-object method + */ + g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL, +- "0:rwx")); ++ PERMISSION_ITEM (PW_ID_CORE, PW_PERM_RWX)); + + /* + * PipeWire:Interface:NodeFactory + * Needs r-- so it can be passed to create-object when creating the sink node. + */ +- node_factory_permission_string = g_strdup_printf ("%d:r--", +- remote->node_factory_id); +- string_stash = g_list_prepend (string_stash, node_factory_permission_string); + g_array_append_val (permission_items, +- PERMISSION_ITEM (PW_CORE_PROXY_PERMISSIONS_GLOBAL, +- node_factory_permission_string)); +- node_global = g_hash_table_lookup (remote->globals, +- GINT_TO_POINTER (remote->node_factory_id)); +- append_parent_permissions (remote, permission_items, &string_stash, +- node_global, "r--"); ++ PERMISSION_ITEM (remote->node_factory_id, PW_PERM_R)); + +- append_stream_permissions (remote, permission_items, &string_stash, streams); ++ append_stream_permissions (remote, permission_items, streams); + +- permission_dict = +- &SPA_DICT_INIT ((struct spa_dict_item *) permission_items->data, +- permission_items->len); +- pw_core_proxy_permissions (pw_remote_get_core_proxy (remote->remote), +- permission_dict); ++ /* ++ * Hide all existing and future nodes (except the ones we explicitly list above). ++ */ ++ g_array_append_val (permission_items, ++ PERMISSION_ITEM (PW_ID_ANY, 0)); + +- g_list_free_full (string_stash, g_free); ++ pw_client_update_permissions (pw_core_get_client(remote->core), ++ permission_items->len, ++ (const struct pw_permission *)permission_items->data); + + pipewire_remote_roundtrip (remote); + +@@ -943,7 +879,7 @@ handle_open_pipewire_remote (XdpScreenCast *object, + } + + out_fd_list = g_unix_fd_list_new (); +- fd = pw_remote_steal_fd (remote->remote); ++ fd = pw_core_steal_fd (remote->core); + fd_id = g_unix_fd_list_append (out_fd_list, fd, &error); + close (fd); + pipewire_remote_destroy (remote); +-- +2.26.2 + diff --git a/SOURCES/0001-open-uri-Return-errors-from-launch_application_with_.patch b/SOURCES/0001-open-uri-Return-errors-from-launch_application_with_.patch new file mode 100644 index 0000000..86b0e68 --- /dev/null +++ b/SOURCES/0001-open-uri-Return-errors-from-launch_application_with_.patch @@ -0,0 +1,77 @@ +From cd57d5729133e1d2f1987271f9437e72c626a93c Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Fri, 17 Apr 2020 17:44:42 +0200 +Subject: [PATCH 1/5] open-uri: Return errors from + launch_application_with_uri() + +--- + src/open-uri.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/src/open-uri.c b/src/open-uri.c +index c876ab6..c0dd94e 100644 +--- a/src/open-uri.c ++++ b/src/open-uri.c +@@ -226,7 +226,8 @@ static gboolean + launch_application_with_uri (const char *choice_id, + const char *uri, + const char *parent_window, +- gboolean writable) ++ gboolean writable, ++ GError **error) + { + g_autofree char *desktop_id = g_strconcat (choice_id, ".desktop", NULL); + g_autoptr(GDesktopAppInfo) info = g_desktop_app_info_new (desktop_id); +@@ -238,14 +239,15 @@ launch_application_with_uri (const char *choice_id, + + if (is_sandboxed (info) && is_file_uri (uri)) + { +- g_autoptr(GError) error = NULL; ++ g_autoptr(GError) local_error = NULL; + + g_debug ("Registering %s for %s", uri, choice_id); + +- ruri = register_document (uri, choice_id, FALSE, writable, &error); ++ ruri = register_document (uri, choice_id, FALSE, writable, &local_error); + if (ruri == NULL) + { +- g_warning ("Error registering %s for %s: %s", uri, choice_id, error->message); ++ g_warning ("Error registering %s for %s: %s", uri, choice_id, local_error->message); ++ g_propagate_error (error, local_error); + return FALSE; + } + } +@@ -257,7 +259,7 @@ launch_application_with_uri (const char *choice_id, + uris.data = (gpointer)ruri; + uris.next = NULL; + +- g_app_info_launch_uris (G_APP_INFO (info), &uris, context, NULL); ++ g_app_info_launch_uris (G_APP_INFO (info), &uris, context, error); + + return TRUE; + } +@@ -354,7 +356,7 @@ send_response_in_thread_func (GTask *task, + writable = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (request), "writable")); + content_type = (const char *)g_object_get_data (G_OBJECT (request), "content-type"); + +- if (launch_application_with_uri (choice, uri, parent_window, writable)) ++ if (launch_application_with_uri (choice, uri, parent_window, writable, NULL)) + update_permissions_store (xdp_app_info_get_id (request->app_info), content_type, choice); + } + +@@ -683,10 +685,11 @@ handle_open_in_thread_func (GTask *task, + if (app) + { + /* Launch the app directly */ ++ g_autoptr(GError) error = NULL; + + g_debug ("Skipping app chooser"); + +- gboolean result = launch_application_with_uri (app, uri, parent_window, writable); ++ gboolean result = launch_application_with_uri (app, uri, parent_window, writable, &error); + if (request->exported) + { + g_variant_builder_init (&opts_builder, G_VARIANT_TYPE_VARDICT); +-- +2.26.2 + diff --git a/SOURCES/0002-open-uri-Allow-skipping-chooser-for-more-URL-types.patch b/SOURCES/0002-open-uri-Allow-skipping-chooser-for-more-URL-types.patch new file mode 100644 index 0000000..34cad89 --- /dev/null +++ b/SOURCES/0002-open-uri-Allow-skipping-chooser-for-more-URL-types.patch @@ -0,0 +1,45 @@ +From 6e6b1ce9230da1936398267c2c39723b4a02a29b Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Thu, 16 Apr 2020 16:31:32 +0200 +Subject: [PATCH 2/5] open-uri: Allow skipping chooser for more URL types + +Also allow skipping the chooser to send mails, open FTP sites, or +calendar items. + +(cherry picked from commit 73928756aeaf1d10fed3486adbce92ba83ff9a6b) +--- + src/open-uri.c | 18 ++++++++++++++---- + 1 file changed, 14 insertions(+), 4 deletions(-) + +diff --git a/src/open-uri.c b/src/open-uri.c +index c0dd94e..35ba644 100644 +--- a/src/open-uri.c ++++ b/src/open-uri.c +@@ -448,10 +448,20 @@ static gboolean + can_skip_app_chooser (const char *scheme, + const char *content_type) + { +- /* We skip the app chooser for Internet URIs, to be open in the browser */ +- /* Skipping the chooser for directories is useful too (e.g. opening in Nautilus) */ +- if (g_strcmp0 (scheme, "http") == 0 || +- g_strcmp0 (scheme, "https") == 0 || ++ const char *skipped_schemes[] = { ++ "http", ++ "https", ++ "ftp", ++ "mailto", ++ "webcal", ++ "calendar", ++ NULL ++ }; ++ ++ /* We skip the app chooser for Internet URIs, to be open in the browser, ++ * mail client, or calendar, as well as for directories to be opened in ++ * the file manager */ ++ if (g_strv_contains (skipped_schemes, scheme) || + g_strcmp0 (content_type, "inode/directory") == 0) + { + g_debug ("Can skip app chooser for %s", content_type); +-- +2.26.2 + diff --git a/SOURCES/0003-open-uri-Always-open-URIs-in-default-app.patch b/SOURCES/0003-open-uri-Always-open-URIs-in-default-app.patch new file mode 100644 index 0000000..1498cce --- /dev/null +++ b/SOURCES/0003-open-uri-Always-open-URIs-in-default-app.patch @@ -0,0 +1,75 @@ +From a82f40b933f1918e7b7c30830b54e713860b8494 Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Thu, 16 Apr 2020 16:38:47 +0200 +Subject: [PATCH 3/5] open-uri: Always open URIs in default app + +Always open URIs and directories in the default application, as both +GNOME and KDE have Settings allowing those to be changed easily. + +(cherry picked from commit 1dbdd31a8f4d4bb5808e85e46bf8fe8443290159) +--- + src/open-uri.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/src/open-uri.c b/src/open-uri.c +index 35ba644..21b180e 100644 +--- a/src/open-uri.c ++++ b/src/open-uri.c +@@ -445,8 +445,8 @@ get_content_type_for_file (const char *path, + } + + static gboolean +-can_skip_app_chooser (const char *scheme, +- const char *content_type) ++should_use_default_app (const char *scheme, ++ const char *content_type) + { + const char *skipped_schemes[] = { + "http", +@@ -562,7 +562,7 @@ handle_open_in_thread_func (GTask *task, + gboolean writable = FALSE; + gboolean ask = FALSE; + gboolean open_dir = FALSE; +- gboolean can_skip = FALSE; ++ gboolean use_default_app = FALSE; + const char *reason; + + parent_window = (const char *)g_object_get_data (G_OBJECT (request), "parent-window"); +@@ -632,7 +632,7 @@ handle_open_in_thread_func (GTask *task, + + /* collect all the information */ + find_recommended_choices (scheme, content_type, &default_app, &choices, &n_choices); +- can_skip = can_skip_app_chooser (scheme, content_type); ++ use_default_app = should_use_default_app (scheme, content_type); + get_latest_choice_info (app_id, content_type, + &latest_id, &latest_count, &latest_threshold, + &ask_for_content_type); +@@ -640,11 +640,10 @@ handle_open_in_thread_func (GTask *task, + skip_app_chooser = FALSE; + reason = NULL; + +- /* apply default handling: skip if the we have a default handler and its http or inode/directory */ +- if (default_app != NULL && can_skip) ++ /* apply default handling: skip if the we have a default handler */ ++ if (default_app != NULL && use_default_app) + { +- if (!skip_app_chooser) +- reason = "Allowing to skip app chooser: can use default"; ++ reason = "Allowing to skip app chooser: can use default"; + skip_app_chooser = TRUE; + } + +@@ -685,7 +684,9 @@ handle_open_in_thread_func (GTask *task, + { + const char *app; + +- if (latest_id != NULL) ++ if (default_app != NULL && use_default_app) ++ app = default_app; ++ else if (latest_id != NULL) + app = latest_id; + else if (default_app != NULL) + app = default_app; +-- +2.26.2 + diff --git a/SOURCES/0004-open-uri-Show-app-chooser-when-default-app-does-not-.patch b/SOURCES/0004-open-uri-Show-app-chooser-when-default-app-does-not-.patch new file mode 100644 index 0000000..fd47797 --- /dev/null +++ b/SOURCES/0004-open-uri-Show-app-chooser-when-default-app-does-not-.patch @@ -0,0 +1,76 @@ +From c056c8ee9eb5401564026a0bb963817073b3bced Mon Sep 17 00:00:00 2001 +From: Bastien Nocera +Date: Thu, 7 May 2020 11:39:27 +0200 +Subject: [PATCH 4/5] open-uri: Show app chooser when default app does not + exist + +Fix a possible crash when the application that would be selected to +avoid the app chooser is not available (anymore). + +This would have happened when eog.desktop got renamed to +org.gnome.eog.desktop but was launched enough times as eog.desktop to +make it the default. + +Based on https://github.com/flatpak/xdg-desktop-portal/pull/481 + +(cherry picked from commit 69205f12cc57542a7c38c1b631fa8a8d9529f5d6) +--- + src/open-uri.c | 17 +++++++++++++++-- + 1 file changed, 15 insertions(+), 2 deletions(-) + +diff --git a/src/open-uri.c b/src/open-uri.c +index 21b180e..1564753 100644 +--- a/src/open-uri.c ++++ b/src/open-uri.c +@@ -535,6 +535,15 @@ app_info_changed (GAppInfoMonitor *monitor, + NULL); + } + ++static gboolean ++app_exists (const char *app_id) ++{ ++ g_autoptr(GDesktopAppInfo) info = NULL; ++ ++ info = g_desktop_app_info_new (app_id); ++ return (info != NULL); ++} ++ + static void + handle_open_in_thread_func (GTask *task, + gpointer source_object, +@@ -632,10 +641,14 @@ handle_open_in_thread_func (GTask *task, + + /* collect all the information */ + find_recommended_choices (scheme, content_type, &default_app, &choices, &n_choices); ++ if (!app_exists (default_app)) ++ g_clear_pointer (&default_app, g_free); + use_default_app = should_use_default_app (scheme, content_type); + get_latest_choice_info (app_id, content_type, + &latest_id, &latest_count, &latest_threshold, + &ask_for_content_type); ++ if (!app_exists (latest_id)) ++ g_clear_pointer (&latest_id, g_free); + + skip_app_chooser = FALSE; + reason = NULL; +@@ -682,7 +695,7 @@ handle_open_in_thread_func (GTask *task, + + if (skip_app_chooser) + { +- const char *app; ++ const char *app = NULL; + + if (default_app != NULL && use_default_app) + app = default_app; +@@ -690,7 +703,7 @@ handle_open_in_thread_func (GTask *task, + app = latest_id; + else if (default_app != NULL) + app = default_app; +- else ++ else if (choices && app_exists (choices[0])) + app = choices[0]; + + if (app) +-- +2.26.2 + diff --git a/SOURCES/0005-open-uri-avoid-criticals-when-app-to-open-does-not-e.patch b/SOURCES/0005-open-uri-avoid-criticals-when-app-to-open-does-not-e.patch new file mode 100644 index 0000000..5174100 --- /dev/null +++ b/SOURCES/0005-open-uri-avoid-criticals-when-app-to-open-does-not-e.patch @@ -0,0 +1,36 @@ +From 5c3b3f4e545812da934ca14164916af297049418 Mon Sep 17 00:00:00 2001 +From: Michael Catanzaro +Date: Fri, 1 May 2020 17:26:54 -0500 +Subject: [PATCH 5/5] open-uri: avoid criticals when app to open does not exist + +If g_desktop_app_info_new() returns NULL, then the desired desktop file +does not exist. Simply return FALSE in this case instead of trying to +use it. + +See: #480 +(cherry picked from commit c41efbe598918fedf01d69f65b581cfbf107b00b) +--- + src/open-uri.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/src/open-uri.c b/src/open-uri.c +index 1564753..dffc008 100644 +--- a/src/open-uri.c ++++ b/src/open-uri.c +@@ -235,6 +235,13 @@ launch_application_with_uri (const char *choice_id, + g_autofree char *ruri = NULL; + GList uris; + ++ if (info == NULL) ++ { ++ g_debug ("Cannot launch %s because desktop file does not exist", desktop_id); ++ g_set_error (error, XDG_DESKTOP_PORTAL_ERROR, XDG_DESKTOP_PORTAL_ERROR_NOT_FOUND, "Desktop file %s does not exist", desktop_id); ++ return FALSE; ++ } ++ + g_debug ("Launching %s %s", choice_id, uri); + + if (is_sandboxed (info) && is_file_uri (uri)) +-- +2.26.2 + diff --git a/SPECS/xdg-desktop-portal.spec b/SPECS/xdg-desktop-portal.spec index 6090b55..a51f974 100644 --- a/SPECS/xdg-desktop-portal.spec +++ b/SPECS/xdg-desktop-portal.spec @@ -1,15 +1,28 @@ -%global pipewire_version 0.2.6 +%global pipewire_version 0.3.0 %global geoclue_version 2.5.2 Name: xdg-desktop-portal -Version: 1.4.2 -Release: 1%{?dist} +Version: 1.6.0 +Release: 2%{?dist} Summary: Portal frontend service to flatpak License: LGPLv2+ URL: https://github.com/flatpak/xdg-desktop-portal/ Source0: https://github.com/flatpak/xdg-desktop-portal/releases/download/%{version}/%{name}-%{version}.tar.xz +# Backport PipeWire 0.3 support (#1775345) +Patch1: 0001-PipeWire-update-to-0.3-API.patch + +# Backport https://github.com/flatpak/xdg-desktop-portal/issues/480 fixes. (#1775345) +Patch2: 0001-open-uri-Return-errors-from-launch_application_with_.patch +Patch3: 0002-open-uri-Allow-skipping-chooser-for-more-URL-types.patch +Patch4: 0003-open-uri-Always-open-URIs-in-default-app.patch +Patch5: 0004-open-uri-Show-app-chooser-when-default-app-does-not-.patch +Patch6: 0005-open-uri-avoid-criticals-when-app-to-open-does-not-e.patch + +# Build against older glib2 +Patch7: 0001-Don-t-use-g_strv_equals.patch + BuildRequires: gcc BuildRequires: pkgconfig(flatpak) BuildRequires: pkgconfig(fontconfig) @@ -17,8 +30,12 @@ BuildRequires: pkgconfig(fuse) BuildRequires: pkgconfig(gio-unix-2.0) BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: pkgconfig(libgeoclue-2.0) >= %{geoclue_version} -BuildRequires: pkgconfig(libpipewire-0.2) >= %{pipewire_version} +BuildRequires: pkgconfig(libpipewire-0.3) >= %{pipewire_version} BuildRequires: /usr/bin/xmlto +BuildRequires: autoconf +BuildRequires: automake +BuildRequires: libtool +BUildRequires: gettext-devel %{?systemd_requires} BuildRequires: systemd Requires: dbus @@ -27,6 +44,10 @@ Recommends: flatpak >= 1.2.0 Requires: geoclue2 >= %{geoclue_version} Recommends: pipewire >= %{pipewire_version} Requires: pipewire-libs >= %{pipewire_version} +# Until WebRTC supports PipeWire 0.3 we have to require PipeWire 0.2 to be +# preinstalled otherwise the screen and window sharing won't work in Chrome and +# Chromium out of the box. +Requires: pipewire0.2-libs%{?_isa} # Required for the document portal. Requires: /usr/bin/fusermount @@ -45,10 +66,11 @@ The pkg-config file for %{name}. %prep -%setup -q +%autosetup -S git %build -%configure --enable-docbook-docs +autoreconf --force --install --verbose +%configure --enable-docbook-docs --disable-libportal %make_build @@ -95,6 +117,15 @@ install -dm 755 %{buildroot}/%{_datadir}/%{name}/portals %changelog +* Thu Jul 15 2020 Jonas Ådahl - 1.6.0-2 +- Require pipewire0.2-libs for legacy application support. + Resolves: #1854734 + +* Mon May 25 2020 Jonas Ådahl - 1.6.0-1 +- Rebase to 1.6.0 (#1775345) +- Backport PipeWire 0.3 support (#1775345) +- Backport fixes (#1775345) + * Wed Oct 09 2019 David King - 1.4.2-1 - Rebase to 1.4.2 (#1748296)