From 718c1ed0da5afe10b78a9b65e0b5e08aaa08b0a4 Mon Sep 17 00:00:00 2001 From: Eva M Date: Tue, 3 Mar 2026 12:58:50 -0700 Subject: [PATCH] init work on full bundle support (WIP) Right now seems to be able to load and open bundles, but installation simply asks for privaleges, then the transaction itself finishes instantly with no apparent effect --- src/bz-application.c | 81 +++++++++++++++++++++++++-------------- src/bz-entry-group.c | 80 -------------------------------------- src/bz-entry-group.h | 3 -- src/bz-flatpak-entry.c | 42 ++++++++++++-------- src/bz-flatpak-entry.h | 4 +- src/bz-flatpak-instance.c | 36 +++++++++++------ src/bz-full-view.blp | 5 --- src/bz-window.c | 20 ---------- src/bz-window.h | 4 -- 9 files changed, 107 insertions(+), 168 deletions(-) diff --git a/src/bz-application.c b/src/bz-application.c index f4632196..b0b75e9d 100644 --- a/src/bz-application.c +++ b/src/bz-application.c @@ -218,7 +218,7 @@ static DexFuture * watch_backend_notifs_then_loop_cb (DexFuture *future, GWeakRef *wr); -static void +static BzEntryGroup * fiber_replace_entry (BzApplication *self, BzEntry *entry); @@ -1119,10 +1119,11 @@ init_fiber (GWeakRef *wr) entries, (GCompareDataFunc) cmp_entry, NULL); for (guint i = 0; i < entries->len; i++) { - BzEntry *entry = NULL; + BzEntry *entry = NULL; + g_autoptr (BzEntryGroup) group = NULL; entry = g_ptr_array_index (entries, i); - fiber_replace_entry (self, entry); + group = fiber_replace_entry (self, entry); } gtk_filter_changed (GTK_FILTER (self->group_filter), GTK_FILTER_CHANGE_LESS_STRICT); @@ -1310,23 +1311,17 @@ respond_to_flatpak_fiber (RespondToFlatpakData *data) break; case BZ_BACKEND_NOTIFICATION_KIND_REPLACE_ENTRY: { - BzEntry *entry = NULL; + BzEntry *entry = NULL; + g_autoptr (BzEntryGroup) group = NULL; entry = bz_backend_notification_get_entry (notif); - fiber_replace_entry (self, entry); + group = fiber_replace_entry (self, entry); g_ptr_array_add (build_futures, bz_entry_cache_manager_add (self->cache, entry)); - if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) + if (group != NULL) { - const char *id = NULL; - BzEntryGroup *group = NULL; - update_filters = TRUE; - - id = bz_entry_get_id (entry); - group = g_hash_table_lookup (self->ids_to_groups, id); - if (group != NULL) - g_ptr_array_add (build_notify_groups, g_object_ref (group)); + g_ptr_array_add (build_notify_groups, g_object_ref (group)); } self->n_notifications_incoming--; @@ -1626,6 +1621,7 @@ open_flatpakref_fiber (OpenFlatpakrefData *data) g_autoptr (BzApplication) self = NULL; GFile *file = data->file; g_autoptr (GError) local_error = NULL; + gboolean result = FALSE; g_autoptr (DexFuture) future = NULL; GtkWindow *window = NULL; const GValue *value = NULL; @@ -1647,14 +1643,36 @@ open_flatpakref_fiber (OpenFlatpakrefData *data) { BzEntry *entry = NULL; - entry = g_value_get_object (value); - bz_window_show_entry (BZ_WINDOW (window), entry); + entry = g_value_get_object (value); + result = dex_await (bz_entry_cache_manager_add (self->cache, entry), &local_error); + if (result) + { + g_autoptr (BzEntryGroup) group = NULL; + + group = fiber_replace_entry (self, entry); + if (group != NULL) + bz_window_show_group (BZ_WINDOW (window), group); + else + /* TODO: handle standalone addons & runtimes in dedicated UI */ + bz_show_error_for_widget ( + GTK_WIDGET (window), + "Non-Application Bundle", + "This flatpak ref is a standalone addon/runtime"); + } + else + bz_show_error_for_widget ( + GTK_WIDGET (window), + _ ("Failed to open package"), + local_error->message); } else open_generic_id (self, g_value_get_string (value)); } else - bz_show_error_for_widget (GTK_WIDGET (window), _ ("Failed to open .flatpakref"), local_error->message); + bz_show_error_for_widget ( + GTK_WIDGET (window), + _ ("Failed to open package"), + local_error->message); return dex_future_new_true (); } @@ -1845,7 +1863,7 @@ watch_backend_notifs_then_loop_cb (DexFuture *future, return g_steal_pointer (&ret_future); } -static void +static BzEntryGroup * fiber_replace_entry (BzApplication *self, BzEntry *entry) { @@ -1856,6 +1874,7 @@ fiber_replace_entry (BzApplication *self, gboolean installed = FALSE; const char *flatpak_id = NULL; const char *version = NULL; + g_autoptr (BzEntryGroup) group = NULL; id = bz_entry_get_id (entry); unique_id = bz_entry_get_unique_id (entry); @@ -1863,7 +1882,7 @@ fiber_replace_entry (BzApplication *self, if (id == NULL || unique_id == NULL || unique_id_checksum == NULL) - return; + return NULL; user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); installed = g_hash_table_contains (self->installed_set, unique_id); @@ -1904,12 +1923,12 @@ fiber_replace_entry (BzApplication *self, if (bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION)) { - BzEntryGroup *group = NULL; - gboolean ignore_eol = FALSE; - const char *runtime_name = NULL; - BzEntry *eol_runtime = NULL; + BzEntryGroup *existing_group = NULL; + gboolean ignore_eol = FALSE; + const char *runtime_name = NULL; + BzEntry *eol_runtime = NULL; - group = g_hash_table_lookup (self->ids_to_groups, id); + existing_group = g_hash_table_lookup (self->ids_to_groups, id); if (self->ignore_eol_set != NULL) ignore_eol = g_hash_table_contains (self->ignore_eol_set, id); @@ -1917,13 +1936,15 @@ fiber_replace_entry (BzApplication *self, if (!ignore_eol && runtime_name != NULL) eol_runtime = g_hash_table_lookup (self->eol_runtimes, runtime_name); - if (group != NULL) + if (existing_group != NULL) { - bz_entry_group_add (group, entry, eol_runtime, ignore_eol); - if (installed && !g_list_store_find (self->installed_apps, group, NULL)) + bz_entry_group_add (existing_group, entry, eol_runtime, ignore_eol); + if (installed && !g_list_store_find (self->installed_apps, existing_group, NULL)) g_list_store_insert_sorted ( - self->installed_apps, group, + self->installed_apps, existing_group, (GCompareDataFunc) cmp_group, NULL); + + group = g_object_ref (existing_group); } else { @@ -1940,6 +1961,8 @@ fiber_replace_entry (BzApplication *self, g_list_store_insert_sorted ( self->installed_apps, new_group, (GCompareDataFunc) cmp_group, NULL); + + group = g_object_ref (new_group); } } @@ -1996,6 +2019,8 @@ fiber_replace_entry (BzApplication *self, "does not seem to extend anything", unique_id); } + + return g_steal_pointer (&group); } static void diff --git a/src/bz-entry-group.c b/src/bz-entry-group.c index d9df0f21..4af6e8a3 100644 --- a/src/bz-entry-group.c +++ b/src/bz-entry-group.c @@ -509,86 +509,6 @@ bz_entry_group_new (BzApplicationMapFactory *factory) return group; } -BzEntryGroup * -bz_entry_group_new_for_single_entry (BzEntry *entry) -{ - BzEntryGroup *group = NULL; - const char *id = NULL; - const char *unique_id = NULL; - const char *title = NULL; - const char *developer = NULL; - const char *description = NULL; - GIcon *mini_icon = NULL; - const char *search_tokens = NULL; - gboolean is_floss = FALSE; - const char *light_accent_color = NULL; - const char *dark_accent_color = NULL; - gboolean is_flathub = FALSE; - gboolean is_verified = FALSE; - const char *eol = NULL; - guint64 installed_size = 0; - const char *donation_url = NULL; - GListModel *entry_categories = NULL; - DexFuture *future = NULL; - - g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL); - - group = g_object_new (BZ_TYPE_ENTRY_GROUP, NULL); - - id = bz_entry_get_id (entry); - unique_id = bz_entry_get_unique_id (entry); - title = bz_entry_get_title (entry); - developer = bz_entry_get_developer (entry); - description = bz_entry_get_description (entry); - mini_icon = bz_entry_get_mini_icon (entry); - search_tokens = bz_entry_get_search_tokens (entry); - is_floss = bz_entry_get_is_foss (entry); - light_accent_color = bz_entry_get_light_accent_color (entry); - dark_accent_color = bz_entry_get_dark_accent_color (entry); - is_flathub = bz_entry_get_is_flathub (entry); - is_verified = bz_entry_is_verified (entry); - eol = bz_entry_get_eol (entry); - installed_size = bz_entry_get_installed_size (entry); - donation_url = bz_entry_get_donation_url (entry); - entry_categories = bz_entry_get_categories (entry); - - if (id != NULL) - group->id = g_strdup (id); - if (title != NULL) - group->title = g_strdup (title); - if (developer != NULL) - group->developer = g_strdup (developer); - if (description != NULL) - group->description = g_strdup (description); - if (mini_icon != NULL) - group->mini_icon = g_object_ref (mini_icon); - if (search_tokens != NULL) - group->search_tokens = g_strdup (search_tokens); - group->is_floss = is_floss; - if (light_accent_color != NULL) - group->light_accent_color = g_strdup (light_accent_color); - if (dark_accent_color != NULL) - group->dark_accent_color = g_strdup (dark_accent_color); - group->is_flathub = is_flathub; - group->is_verified = is_verified; - if (eol != NULL) - group->eol = g_strdup (eol); - group->installed_size = installed_size; - if (donation_url != NULL) - group->donation_url = g_strdup (donation_url); - if (entry_categories != NULL) - group->categories = g_object_ref (entry_categories); - - if (unique_id != NULL) - gtk_string_list_append (group->unique_ids, unique_id); - - future = dex_future_new_for_object (entry); - group->standalone_ui_entry = bz_result_new (future); - dex_unref (future); - - return group; -} - GMutexLocker * bz_entry_group_lock (BzEntryGroup *self) { diff --git a/src/bz-entry-group.h b/src/bz-entry-group.h index 88a5133d..dd6b6f2a 100644 --- a/src/bz-entry-group.h +++ b/src/bz-entry-group.h @@ -32,9 +32,6 @@ G_DECLARE_FINAL_TYPE (BzEntryGroup, bz_entry_group, BZ, ENTRY_GROUP, GObject) BzEntryGroup * bz_entry_group_new (BzApplicationMapFactory *factory); -BzEntryGroup * -bz_entry_group_new_for_single_entry (BzEntry *entry); - /* Only necessary if reading props from another thread, writing is always prohibited */ GMutexLocker * diff --git a/src/bz-flatpak-entry.c b/src/bz-flatpak-entry.c index bd155198..5aefcf32 100644 --- a/src/bz-flatpak-entry.c +++ b/src/bz-flatpak-entry.c @@ -41,8 +41,8 @@ struct _BzFlatpakEntry BzEntry parent_instance; gboolean user; - gboolean is_bundle; gboolean is_installed_ref; + char *bundle_uri; char *flatpak_name; char *flatpak_id; char *flatpak_version; @@ -71,7 +71,7 @@ enum PROP_USER, PROP_FLATPAK_NAME, - PROP_IS_BUNDLE, + PROP_BUNDLE_URI, PROP_FLATPAK_ID, PROP_FLATPAK_VERSION, PROP_APPLICATION_NAME, @@ -124,8 +124,8 @@ bz_flatpak_entry_get_property (GObject *object, case PROP_APPLICATION_NAME: g_value_set_string (value, self->application_name); break; - case PROP_IS_BUNDLE: - g_value_set_boolean (value, self->is_bundle); + case PROP_BUNDLE_URI: + g_value_set_string (value, self->bundle_uri); break; case PROP_APPLICATION_RUNTIME: g_value_set_string (value, self->application_runtime); @@ -162,7 +162,7 @@ bz_flatpak_entry_set_property (GObject *object, case PROP_FLATPAK_ID: case PROP_FLATPAK_VERSION: case PROP_APPLICATION_NAME: - case PROP_IS_BUNDLE: + case PROP_BUNDLE_URI: case PROP_APPLICATION_RUNTIME: case PROP_APPLICATION_COMMAND: case PROP_RUNTIME_NAME: @@ -212,11 +212,10 @@ bz_flatpak_entry_class_init (BzFlatpakEntryClass *klass) NULL, NULL, NULL, G_PARAM_READABLE); - props[PROP_IS_BUNDLE] = - g_param_spec_boolean ( - "is-bundle", - NULL, NULL, - FALSE, + props[PROP_BUNDLE_URI] = + g_param_spec_string ( + "bundle-uri", + NULL, NULL, NULL, G_PARAM_READABLE); props[PROP_APPLICATION_RUNTIME] = @@ -266,6 +265,8 @@ bz_flatpak_entry_real_serialize (BzSerializable *serializable, g_variant_builder_add (builder, "{sv}", "user", g_variant_new_boolean (self->user)); g_variant_builder_add (builder, "{sv}", "is-installed-ref", g_variant_new_boolean (self->is_installed_ref)); + if (self->bundle_uri != NULL) + g_variant_builder_add (builder, "{sv}", "bundle-uri", g_variant_new_string (self->bundle_uri)); if (self->flatpak_name != NULL) g_variant_builder_add (builder, "{sv}", "flatpak-name", g_variant_new_string (self->flatpak_name)); if (self->flatpak_id != NULL) @@ -309,6 +310,8 @@ bz_flatpak_entry_real_deserialize (BzSerializable *serializable, self->user = g_variant_get_boolean (value); else if (g_strcmp0 (key, "is-installed-ref") == 0) self->is_installed_ref = g_variant_get_boolean (value); + else if (g_strcmp0 (key, "bundle-uri") == 0) + self->bundle_uri = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "flatpak-name") == 0) self->flatpak_name = g_variant_dup_string (value, NULL); else if (g_strcmp0 (key, "flatpak-id") == 0) @@ -400,7 +403,6 @@ bz_flatpak_entry_new_for_ref (FlatpakRef *ref, self = g_object_new (BZ_TYPE_FLATPAK_ENTRY, NULL); self->user = user; - self->is_bundle = FLATPAK_IS_BUNDLE_REF (ref); self->is_installed_ref = FLATPAK_IS_INSTALLED_REF (ref); self->ref = g_object_ref (ref); @@ -505,8 +507,17 @@ bz_flatpak_entry_new_for_ref (FlatpakRef *ref, else if (FLATPAK_IS_BUNDLE_REF (ref)) { g_autoptr (GFileInfo) file_info = NULL; + g_autoptr (GFile) bundle_file = NULL; - GFile *bundle_file = flatpak_bundle_ref_get_file (FLATPAK_BUNDLE_REF (ref)); + bundle_file = flatpak_bundle_ref_get_file (FLATPAK_BUNDLE_REF (ref)); + self->bundle_uri = g_file_get_uri (bundle_file); + if (self->bundle_uri == NULL) + { + g_autofree char *path = NULL; + + path = g_file_get_path (bundle_file); + self->bundle_uri = g_strdup_printf ("file://%s", path); + } file_info = g_file_query_info (bundle_file, G_FILE_ATTRIBUTE_STANDARD_SIZE, @@ -754,11 +765,11 @@ bz_flatpak_entry_get_addon_extension_of_ref (BzFlatpakEntry *self) return self->addon_extension_of_ref; } -gboolean -bz_flatpak_entry_is_bundle (BzFlatpakEntry *self) +const char * +bz_flatpak_entry_get_bundle_uri (BzFlatpakEntry *self) { g_return_val_if_fail (BZ_IS_FLATPAK_ENTRY (self), FALSE); - return self->is_bundle; + return self->bundle_uri; } gboolean @@ -816,6 +827,7 @@ bz_flatpak_entry_launch (BzFlatpakEntry *self, static void clear_entry (BzFlatpakEntry *self) { + g_clear_pointer (&self->bundle_uri, g_free); g_clear_pointer (&self->flatpak_name, g_free); g_clear_pointer (&self->flatpak_id, g_free); g_clear_pointer (&self->flatpak_version, g_free); diff --git a/src/bz-flatpak-entry.h b/src/bz-flatpak-entry.h index 5c85e1c2..a11cc488 100644 --- a/src/bz-flatpak-entry.h +++ b/src/bz-flatpak-entry.h @@ -57,8 +57,8 @@ bz_flatpak_entry_get_runtime_name (BzFlatpakEntry *self); BzResult * bz_flatpak_entry_dup_runtime_result (BzFlatpakEntry *self); -gboolean -bz_flatpak_entry_is_bundle (BzFlatpakEntry *self); +const char * +bz_flatpak_entry_get_bundle_uri (BzFlatpakEntry *self); gboolean bz_flatpak_entry_is_installed_ref (BzFlatpakEntry *self); diff --git a/src/bz-flatpak-instance.c b/src/bz-flatpak-instance.c index 24d4ce22..59b54b35 100644 --- a/src/bz-flatpak-instance.c +++ b/src/bz-flatpak-instance.c @@ -958,7 +958,7 @@ load_local_ref_fiber (LoadLocalRefData *data) return dex_future_new_take_string (g_steal_pointer (&name)); } else - /* This is a bundle ref */ + /* Otherwise, this is a bundle ref */ { g_autoptr (FlatpakBundleRef) bref = NULL; g_autoptr (BzFlatpakEntry) entry = NULL; @@ -1813,13 +1813,15 @@ transaction_fiber (TransactionData *data) BzFlatpakEntry *entry = NULL; FlatpakRef *ref = NULL; gboolean is_user = FALSE; + const char *bundle_uri = NULL; g_autofree char *ref_fmt = NULL; g_autoptr (FlatpakTransaction) transaction = NULL; - entry = g_ptr_array_index (installations, i); - ref = bz_flatpak_entry_get_ref (entry); - is_user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); - ref_fmt = flatpak_ref_format_ref (ref); + entry = g_ptr_array_index (installations, i); + ref = bz_flatpak_entry_get_ref (entry); + is_user = bz_flatpak_entry_is_user (BZ_FLATPAK_ENTRY (entry)); + bundle_uri = bz_flatpak_entry_get_bundle_uri (entry); + ref_fmt = flatpak_ref_format_ref (ref); if ((is_user && self->user == NULL) || (!is_user && self->system == NULL)) @@ -1848,12 +1850,24 @@ transaction_fiber (TransactionData *data) local_error->message); } - result = flatpak_transaction_add_install ( - transaction, - bz_entry_get_remote_repo_name (BZ_ENTRY (entry)), - ref_fmt, - NULL, - &local_error); + if (bundle_uri != NULL) + { + g_autoptr (GFile) file = NULL; + + file = g_file_new_for_uri (bundle_uri); + result = flatpak_transaction_add_install_bundle ( + transaction, + file, + NULL, + &local_error); + } + else + result = flatpak_transaction_add_install ( + transaction, + bz_entry_get_remote_repo_name (BZ_ENTRY (entry)), + ref_fmt, + NULL, + &local_error); if (!result) { dex_channel_close_send (channel); diff --git a/src/bz-full-view.blp b/src/bz-full-view.blp index 2812b6c7..a3fb06d4 100644 --- a/src/bz-full-view.blp +++ b/src/bz-full-view.blp @@ -126,11 +126,6 @@ template $BzFullView: Adw.Bin { margin-bottom: 15; spacing: 20; - Adw.Banner { - title: _("Installing .flatpak bundles is not yet supported"); - revealed: bind template.ui-entry as <$BzResult>.object as <$BzFlatpakEntry>.is-bundle as ; - } - Adw.Clamp { maximum-size: 860; tightening-threshold: 1000; diff --git a/src/bz-window.c b/src/bz-window.c index ad04032a..e5cc7e64 100644 --- a/src/bz-window.c +++ b/src/bz-window.c @@ -883,26 +883,6 @@ bz_window_search (BzWindow *self, search (self, text); } -void -bz_window_show_entry (BzWindow *self, - BzEntry *entry) -{ - g_autoptr (BzEntryGroup) group = NULL; - AdwNavigationPage *view_page = NULL; - - g_return_if_fail (BZ_IS_WINDOW (self)); - g_return_if_fail (BZ_IS_ENTRY (entry)); - - group = bz_entry_group_new_for_single_entry (entry); - bz_full_view_set_entry_group (self->full_view, group); - - view_page = adw_navigation_view_find_page (self->navigation_view, "view"); - if (view_page != NULL) - adw_navigation_view_pop_to_page (self->navigation_view, view_page); - else - adw_navigation_view_push_by_tag (self->navigation_view, "view"); -} - void bz_window_show_group (BzWindow *self, BzEntryGroup *group) diff --git a/src/bz-window.h b/src/bz-window.h index 7f58d6b4..c0fa0bd4 100644 --- a/src/bz-window.h +++ b/src/bz-window.h @@ -39,10 +39,6 @@ bz_window_search (BzWindow *self, void bz_window_push_update_dialog (BzWindow *self); -void -bz_window_show_entry (BzWindow *self, - BzEntry *entry); - void bz_window_show_group (BzWindow *self, BzEntryGroup *group);