Merge branch 'permission-update' into 'main'
updates: Add additional permissions confirmation dialog See merge request World/bazaar!2003
This commit is contained in:
commit
928101c09a
18 changed files with 1167 additions and 901 deletions
|
|
@ -93,6 +93,7 @@ src/bz-login-page.blp
|
|||
src/bz-login-page.c
|
||||
src/bz-login-page.h
|
||||
src/bz-metainfo-preview.c
|
||||
src/bz-new-permissions-dialog.vala
|
||||
src/bz-other-sources-list.vala
|
||||
src/bz-preferences-dialog.blp
|
||||
src/bz-preferences-dialog.c
|
||||
|
|
@ -134,7 +135,7 @@ src/bz-transaction-tile.blp
|
|||
src/bz-transaction-tile.c
|
||||
src/bz-transaction.c
|
||||
src/bz-updates-card.blp
|
||||
src/bz-updates-card.c
|
||||
src/bz-updates-card.vala
|
||||
src/bz-update-history-dialog.blp
|
||||
src/bz-update-history-dialog.c
|
||||
src/bz-user-data-page.blp
|
||||
|
|
|
|||
|
|
@ -105,6 +105,21 @@ static guint app_permissions_get_array_index (GPtrArray *array,
|
|||
const char *subpath);
|
||||
static guint get_strv_index (const gchar *const *strv,
|
||||
const gchar *value);
|
||||
static gboolean array_contains_filesystem_path (GPtrArray *array,
|
||||
BzFilesystemPathType type,
|
||||
const char *subpath);
|
||||
static int bus_policy_compare (const BzBusPolicy *policy1,
|
||||
const BzBusPolicy *policy2);
|
||||
static int bus_policy_compare_lopsided_with_permissions (const BzBusPolicy *policy1,
|
||||
const BzBusPolicy *policy2);
|
||||
static BzBusPolicy *bus_policy_copy (const BzBusPolicy *policy,
|
||||
void *user_data);
|
||||
static GPtrArray *ptr_array_diff (GPtrArray *array1,
|
||||
GPtrArray *array2,
|
||||
GCompareFunc compare_func,
|
||||
GCopyFunc copy_func,
|
||||
void *copy_func_data,
|
||||
GDestroyNotify free_func);
|
||||
|
||||
static void
|
||||
bz_app_permissions_finalize (GObject *object)
|
||||
|
|
@ -322,6 +337,159 @@ bz_app_permissions_is_empty (BzAppPermissions *self)
|
|||
(self->bus_policies == NULL || self->bus_policies->len == 0));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
array_contains_filesystem_path (GPtrArray *array,
|
||||
BzFilesystemPathType type,
|
||||
const char *subpath)
|
||||
{
|
||||
if (array == NULL)
|
||||
return FALSE;
|
||||
|
||||
for (guint i = 0; i < array->len; i++)
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (array, i);
|
||||
if (path->type == type && g_strcmp0 (path->subpath, subpath) == 0)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
bus_policy_compare (const BzBusPolicy *policy1,
|
||||
const BzBusPolicy *policy2)
|
||||
{
|
||||
if (policy1->bus_type != policy2->bus_type)
|
||||
return policy1->bus_type - policy2->bus_type;
|
||||
|
||||
return strcmp (policy1->bus_name, policy2->bus_name);
|
||||
}
|
||||
|
||||
static int
|
||||
bus_policy_compare_lopsided_with_permissions (const BzBusPolicy *policy1,
|
||||
const BzBusPolicy *policy2)
|
||||
{
|
||||
int compare_keys = bus_policy_compare (policy1, policy2);
|
||||
|
||||
if (compare_keys != 0)
|
||||
return compare_keys;
|
||||
|
||||
if (policy2->permission > policy1->permission)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static BzBusPolicy *
|
||||
bus_policy_copy (const BzBusPolicy *policy,
|
||||
void *user_data)
|
||||
{
|
||||
return bz_bus_policy_new (policy->bus_type, policy->bus_name, policy->permission);
|
||||
}
|
||||
|
||||
static GPtrArray *
|
||||
ptr_array_diff (GPtrArray *array1,
|
||||
GPtrArray *array2,
|
||||
GCompareFunc compare_func,
|
||||
GCopyFunc copy_func,
|
||||
void *copy_func_data,
|
||||
GDestroyNotify free_func)
|
||||
{
|
||||
g_autoptr (GPtrArray) diff = NULL;
|
||||
|
||||
if (array2 == NULL)
|
||||
return NULL;
|
||||
if (array1 == NULL)
|
||||
return g_ptr_array_copy (array2, copy_func, copy_func_data);
|
||||
|
||||
diff = g_ptr_array_new_with_free_func (free_func);
|
||||
|
||||
for (unsigned int index1 = 0, index2 = 0;
|
||||
index1 < array1->len || index2 < array2->len;
|
||||
)
|
||||
{
|
||||
const void *element1, *element2;
|
||||
int comparison;
|
||||
|
||||
if (index1 >= array1->len)
|
||||
{
|
||||
element2 = g_ptr_array_index (array2, index2);
|
||||
comparison = 1;
|
||||
}
|
||||
else if (index2 >= array2->len)
|
||||
{
|
||||
element1 = g_ptr_array_index (array1, index1);
|
||||
comparison = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
element1 = g_ptr_array_index (array1, index1);
|
||||
element2 = g_ptr_array_index (array2, index2);
|
||||
comparison = compare_func (element1, element2);
|
||||
}
|
||||
|
||||
if (comparison < 0)
|
||||
{
|
||||
index1++;
|
||||
}
|
||||
else if (comparison == 0)
|
||||
{
|
||||
index1++;
|
||||
index2++;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_ptr_array_add (diff, copy_func (element2, copy_func_data));
|
||||
index2++;
|
||||
}
|
||||
}
|
||||
|
||||
return (diff->len > 0) ? g_steal_pointer (&diff) : NULL;
|
||||
}
|
||||
|
||||
// this is all from GNOME Software
|
||||
BzAppPermissions *
|
||||
bz_app_permissions_diff (BzAppPermissions *self,
|
||||
BzAppPermissions *other)
|
||||
{
|
||||
g_autoptr (BzAppPermissions) diff = bz_app_permissions_new ();
|
||||
const GPtrArray *new_paths;
|
||||
|
||||
g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (self), NULL);
|
||||
g_return_val_if_fail (self->is_sealed, NULL);
|
||||
g_return_val_if_fail (BZ_IS_APP_PERMISSIONS (other), NULL);
|
||||
g_return_val_if_fail (other->is_sealed, NULL);
|
||||
|
||||
bz_app_permissions_set_flags (diff, other->flags & ~self->flags);
|
||||
|
||||
new_paths = bz_app_permissions_get_filesystem_read (other);
|
||||
for (guint i = 0; new_paths != NULL && i < new_paths->len; i++)
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (new_paths, i);
|
||||
|
||||
if (!array_contains_filesystem_path (self->filesystem_read, path->type, path->subpath))
|
||||
bz_app_permissions_add_filesystem_read (diff, path->type, path->subpath);
|
||||
}
|
||||
|
||||
new_paths = bz_app_permissions_get_filesystem_full (other);
|
||||
for (guint i = 0; new_paths != NULL && i < new_paths->len; i++)
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (new_paths, i);
|
||||
|
||||
if (!array_contains_filesystem_path (self->filesystem_full, path->type, path->subpath))
|
||||
bz_app_permissions_add_filesystem_full (diff, path->type, path->subpath);
|
||||
}
|
||||
|
||||
diff->bus_policies = ptr_array_diff (self->bus_policies, other->bus_policies,
|
||||
(GCompareFunc) bus_policy_compare_lopsided_with_permissions,
|
||||
(GCopyFunc) bus_policy_copy, NULL,
|
||||
(GDestroyNotify) bz_bus_policy_free);
|
||||
|
||||
bz_app_permissions_seal (diff);
|
||||
|
||||
return g_steal_pointer (&diff);
|
||||
}
|
||||
|
||||
void
|
||||
bz_app_permissions_set_flags (BzAppPermissions *self,
|
||||
BzAppPermissionsFlags flags)
|
||||
|
|
|
|||
|
|
@ -187,6 +187,10 @@ const BzBusPolicy *const *
|
|||
bz_app_permissions_get_bus_policies (BzAppPermissions *self,
|
||||
size_t *out_n_bus_policies);
|
||||
|
||||
BzAppPermissions *
|
||||
bz_app_permissions_diff (BzAppPermissions *self,
|
||||
BzAppPermissions *other);
|
||||
|
||||
void
|
||||
bz_app_permissions_serialize (BzAppPermissions *self,
|
||||
GVariantBuilder *builder);
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@
|
|||
#include "bz-serializable.h"
|
||||
#include "bz-state-info.h"
|
||||
#include "bz-transaction-manager.h"
|
||||
#include "bz-update-info.h"
|
||||
#include "bz-window.h"
|
||||
#include "bz-yaml-parser.h"
|
||||
#include "dex-utils.h"
|
||||
|
|
@ -2762,9 +2763,9 @@ fiber_replace_entry (BzApplication *self,
|
|||
static void
|
||||
fiber_check_for_updates (BzApplication *self)
|
||||
{
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
g_autoptr (GPtrArray) update_ids = NULL;
|
||||
GtkWindow *window = NULL;
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
g_autoptr (GHashTable) update_ids = NULL;
|
||||
GtkWindow *window = NULL;
|
||||
|
||||
g_debug ("Checking for updates...");
|
||||
bz_state_info_set_background_task_label (self->state, _ ("Checking for updates…"));
|
||||
|
|
@ -2775,17 +2776,24 @@ fiber_check_for_updates (BzApplication *self)
|
|||
&local_error);
|
||||
window = gtk_application_get_active_window (GTK_APPLICATION (self));
|
||||
if (update_ids != NULL &&
|
||||
update_ids->len > 0)
|
||||
g_hash_table_size (update_ids) > 0)
|
||||
{
|
||||
g_autoptr (GPtrArray) futures = NULL;
|
||||
g_autoptr (GListStore) store = NULL;
|
||||
g_autoptr (GPtrArray) unique_ids = NULL;
|
||||
g_autoptr (GPtrArray) futures = NULL;
|
||||
g_autoptr (GListStore) store = NULL;
|
||||
GHashTableIter iter;
|
||||
gpointer key = NULL;
|
||||
gpointer value = NULL;
|
||||
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
for (guint i = 0; i < update_ids->len; i++)
|
||||
unique_ids = g_ptr_array_new ();
|
||||
futures = g_ptr_array_new_with_free_func (dex_unref);
|
||||
|
||||
g_hash_table_iter_init (&iter, update_ids);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
const char *unique_id = NULL;
|
||||
const char *unique_id = key;
|
||||
|
||||
unique_id = g_ptr_array_index (update_ids, i);
|
||||
g_ptr_array_add (unique_ids, (gpointer) unique_id);
|
||||
g_ptr_array_add (futures, bz_entry_cache_manager_get (self->cache, unique_id));
|
||||
}
|
||||
|
||||
|
|
@ -2793,22 +2801,34 @@ fiber_check_for_updates (BzApplication *self)
|
|||
dex_future_allv ((DexFuture *const *) futures->pdata, futures->len),
|
||||
NULL);
|
||||
|
||||
store = g_list_store_new (BZ_TYPE_ENTRY);
|
||||
store = g_list_store_new (BZ_TYPE_UPDATE_PERMISSION_INFO);
|
||||
for (guint i = 0; i < futures->len; i++)
|
||||
{
|
||||
DexFuture *future = NULL;
|
||||
const GValue *value = NULL;
|
||||
DexFuture *future = NULL;
|
||||
const GValue *value_out = NULL;
|
||||
const char *unique_id = NULL;
|
||||
|
||||
future = g_ptr_array_index (futures, i);
|
||||
value = dex_future_get_value (future, &local_error);
|
||||
future = g_ptr_array_index (futures, i);
|
||||
unique_id = g_ptr_array_index (unique_ids, i);
|
||||
value_out = dex_future_get_value (future, &local_error);
|
||||
|
||||
if (value != NULL)
|
||||
g_list_store_append (store, g_value_get_object (value));
|
||||
if (value_out != NULL)
|
||||
{
|
||||
g_autoptr (BzUpdatePermissionInfo) info = NULL;
|
||||
BzAppPermissions *delta = NULL;
|
||||
|
||||
delta = g_hash_table_lookup (update_ids, unique_id);
|
||||
|
||||
info = g_object_new (
|
||||
BZ_TYPE_UPDATE_PERMISSION_INFO,
|
||||
"entry", g_value_get_object (value_out),
|
||||
"additional-permissions", delta,
|
||||
NULL);
|
||||
|
||||
g_list_store_append (store, info);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *unique_id = NULL;
|
||||
|
||||
unique_id = g_ptr_array_index (update_ids, i);
|
||||
g_warning ("%s could not be resolved for the update list and thus will not be included: %s",
|
||||
unique_id, local_error->message);
|
||||
g_clear_pointer (&local_error, g_error_free);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "bz-app-permissions.h"
|
||||
#include "bz-backend-notification.h"
|
||||
#include "bz-backend-transaction-op-payload.h"
|
||||
#include "bz-backend-transaction-op-progress-payload.h"
|
||||
|
|
@ -1889,7 +1890,7 @@ retrieve_refs_for_remote_fiber (RetrieveRefsForRemoteData *data)
|
|||
|
||||
#ifdef SANDBOXED_LIBFLATPAK
|
||||
if (is_noenumerate ||
|
||||
(installation == self->user && !is_whitelisted_user))
|
||||
(installation == self->user && !is_whitelisted_user))
|
||||
#else
|
||||
if (is_noenumerate)
|
||||
#endif
|
||||
|
|
@ -2012,7 +2013,7 @@ retrieve_updates_fiber (GatherRefsData *data)
|
|||
guint n_sys_refs = 0;
|
||||
g_autoptr (GPtrArray) user_refs = NULL;
|
||||
guint n_user_refs = 0;
|
||||
g_autoptr (GPtrArray) ids = NULL;
|
||||
g_autoptr (GHashTable) ids = NULL;
|
||||
|
||||
bz_weak_get_or_return_reject (self, data->self);
|
||||
|
||||
|
|
@ -2046,33 +2047,94 @@ retrieve_updates_fiber (GatherRefsData *data)
|
|||
n_user_refs = user_refs->len;
|
||||
}
|
||||
|
||||
ids = g_ptr_array_new_with_free_func (g_free);
|
||||
ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
||||
|
||||
for (guint i = 0; i < n_sys_refs + n_user_refs; i++)
|
||||
{
|
||||
gboolean user = FALSE;
|
||||
FlatpakInstalledRef *iref = NULL;
|
||||
gboolean user = FALSE;
|
||||
FlatpakInstalledRef *iref = NULL;
|
||||
FlatpakInstallation *installation = NULL;
|
||||
g_autofree char *unique_id = NULL;
|
||||
const char *origin = NULL;
|
||||
g_autoptr (GBytes) old_bytes = NULL;
|
||||
g_autoptr (GKeyFile) old_keyfile = NULL;
|
||||
g_autoptr (GBytes) new_bytes = NULL;
|
||||
g_autoptr (GKeyFile) new_keyfile = NULL;
|
||||
g_autoptr (BzAppPermissions) old_perm = NULL;
|
||||
g_autoptr (BzAppPermissions) new_perm = NULL;
|
||||
BzAppPermissions *delta = NULL;
|
||||
g_autoptr (GError) perm_error = NULL;
|
||||
|
||||
if (i < n_sys_refs)
|
||||
{
|
||||
user = FALSE;
|
||||
iref = g_ptr_array_index (system_refs, i);
|
||||
user = FALSE;
|
||||
iref = g_ptr_array_index (system_refs, i);
|
||||
installation = self->system;
|
||||
}
|
||||
else
|
||||
{
|
||||
user = TRUE;
|
||||
iref = g_ptr_array_index (user_refs, i - n_sys_refs);
|
||||
user = TRUE;
|
||||
iref = g_ptr_array_index (user_refs, i - n_sys_refs);
|
||||
installation = self->user;
|
||||
}
|
||||
|
||||
if (should_skip_extension_ref (iref))
|
||||
continue;
|
||||
|
||||
g_ptr_array_add (ids,
|
||||
bz_flatpak_ref_format_unique (FLATPAK_REF (iref), user));
|
||||
unique_id = bz_flatpak_ref_format_unique (FLATPAK_REF (iref), user);
|
||||
|
||||
old_bytes = flatpak_installed_ref_load_metadata (iref, cancellable, &perm_error);
|
||||
if (old_bytes != NULL)
|
||||
{
|
||||
old_keyfile = g_key_file_new ();
|
||||
if (!g_key_file_load_from_bytes (old_keyfile, old_bytes, G_KEY_FILE_NONE, NULL))
|
||||
g_clear_pointer (&old_keyfile, g_key_file_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Failed to get installed metadata for '%s': %s",
|
||||
flatpak_ref_get_name (FLATPAK_REF (iref)), perm_error->message);
|
||||
}
|
||||
g_clear_error (&perm_error);
|
||||
|
||||
origin = flatpak_installed_ref_get_origin (iref);
|
||||
if (old_keyfile != NULL && origin != NULL)
|
||||
{
|
||||
new_bytes = flatpak_installation_fetch_remote_metadata_sync (
|
||||
installation, origin, FLATPAK_REF (iref), cancellable, &perm_error);
|
||||
if (new_bytes != NULL)
|
||||
{
|
||||
new_keyfile = g_key_file_new ();
|
||||
if (!g_key_file_load_from_bytes (new_keyfile, new_bytes, G_KEY_FILE_NONE, NULL))
|
||||
g_clear_pointer (&new_keyfile, g_key_file_unref);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_debug ("Failed to fetch remote metadata for '%s' from '%s': %s",
|
||||
flatpak_ref_get_name (FLATPAK_REF (iref)), origin, perm_error->message);
|
||||
}
|
||||
}
|
||||
g_clear_error (&perm_error);
|
||||
|
||||
if (old_keyfile != NULL && new_keyfile != NULL)
|
||||
{
|
||||
old_perm = bz_app_permissions_new_from_metadata (old_keyfile, NULL);
|
||||
new_perm = bz_app_permissions_new_from_metadata (new_keyfile, NULL);
|
||||
}
|
||||
|
||||
if (old_perm != NULL && new_perm != NULL)
|
||||
delta = bz_app_permissions_diff (old_perm, new_perm);
|
||||
else
|
||||
{
|
||||
delta = bz_app_permissions_new ();
|
||||
bz_app_permissions_seal (delta);
|
||||
}
|
||||
|
||||
g_hash_table_replace (ids, g_steal_pointer (&unique_id), delta);
|
||||
}
|
||||
|
||||
return dex_future_new_take_boxed (
|
||||
G_TYPE_PTR_ARRAY, g_steal_pointer (&ids));
|
||||
G_TYPE_HASH_TABLE, g_steal_pointer (&ids));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "bz-install-controls.h"
|
||||
#include "bz-state-info.h"
|
||||
#include "bz-update-info.h"
|
||||
#include "progress-bar-designs/common.h"
|
||||
#include "template-callbacks.h"
|
||||
#include "util.h"
|
||||
|
|
@ -190,11 +191,13 @@ find_matching_updates (BzInstallControls *self,
|
|||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr (BzEntry) entry = NULL;
|
||||
const char *id = NULL;
|
||||
g_autoptr (BzUpdatePermissionInfo) info = NULL;
|
||||
BzEntry *entry = NULL;
|
||||
const char *id = NULL;
|
||||
|
||||
entry = g_list_model_get_item (available_updates, i);
|
||||
id = bz_entry_get_id (entry);
|
||||
info = g_list_model_get_item (available_updates, i);
|
||||
entry = bz_update_permission_info_get_entry (info);
|
||||
id = entry != NULL ? bz_entry_get_id (entry) : NULL;
|
||||
|
||||
if (g_strcmp0 (id, group_id) == 0)
|
||||
g_list_store_append (store, entry);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <bzvala.h>
|
||||
|
||||
#include "bz-entry-group.h"
|
||||
#include "bz-installed-tile.h"
|
||||
|
|
@ -26,7 +27,6 @@
|
|||
#include "bz-search-bar.h"
|
||||
#include "bz-section-view.h"
|
||||
#include "bz-transaction-tile.h"
|
||||
#include "bz-updates-card.h"
|
||||
#include "template-callbacks.h"
|
||||
#include "util.h"
|
||||
|
||||
|
|
|
|||
202
src/bz-new-permissions-dialog.vala
Normal file
202
src/bz-new-permissions-dialog.vala
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* bz-new-permissions-dialog.vala
|
||||
*
|
||||
* Copyright 2026 Alexander Vanhee
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
public class Bz.NewPermissionsDialog : Adw.Dialog {
|
||||
private Dex.Promise promise;
|
||||
private bool responded = false;
|
||||
|
||||
private NewPermissionsDialog (Bz.UpdatePermissionInfo[] infos) {
|
||||
Object ();
|
||||
|
||||
content_width = 420;
|
||||
title = _("New Permissions");
|
||||
|
||||
var box = new Gtk.Box (Gtk.Orientation.VERTICAL, 12) {
|
||||
margin_top = 12,
|
||||
margin_bottom = 8,
|
||||
margin_start = 18,
|
||||
margin_end = 18,
|
||||
};
|
||||
|
||||
if (infos.length == 1)
|
||||
build_single_layout (box, infos[0]);
|
||||
else
|
||||
build_multi_layout (box, infos);
|
||||
|
||||
var scrolled_window = new Gtk.ScrolledWindow () {
|
||||
hscrollbar_policy = Gtk.PolicyType.NEVER,
|
||||
vexpand = true,
|
||||
propagate_natural_height = true,
|
||||
child = box,
|
||||
};
|
||||
|
||||
var confirm_button = new Gtk.Button.with_mnemonic (_("_Accept")) {
|
||||
halign = Gtk.Align.CENTER,
|
||||
margin_top = 12,
|
||||
margin_bottom = 18,
|
||||
};
|
||||
confirm_button.add_css_class ("suggested-action");
|
||||
confirm_button.add_css_class ("pill");
|
||||
confirm_button.clicked.connect (() => {
|
||||
responded = true;
|
||||
promise.resolve_boolean (true);
|
||||
close ();
|
||||
});
|
||||
|
||||
var toolbar_view = new Adw.ToolbarView ();
|
||||
toolbar_view.add_top_bar (new Adw.HeaderBar () {show_title = infos.length > 1});
|
||||
toolbar_view.content = scrolled_window;
|
||||
toolbar_view.add_bottom_bar (confirm_button);
|
||||
|
||||
child = toolbar_view;
|
||||
|
||||
promise = new Dex.Promise ();
|
||||
|
||||
this.closed.connect (() => {
|
||||
if (!responded) {
|
||||
responded = true;
|
||||
promise.resolve_boolean (false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void build_single_layout (Gtk.Box box, Bz.UpdatePermissionInfo info) {
|
||||
var status_page = new Adw.StatusPage () {
|
||||
vexpand = false,
|
||||
};
|
||||
status_page.add_css_class ("compact");
|
||||
|
||||
var permissions_list = new Gtk.ListBox () {
|
||||
selection_mode = Gtk.SelectionMode.NONE,
|
||||
};
|
||||
permissions_list.add_css_class ("boxed-list");
|
||||
|
||||
var group = new Adw.PreferencesGroup ();
|
||||
group.add (permissions_list);
|
||||
|
||||
box.append (status_page);
|
||||
box.append (group);
|
||||
|
||||
status_page.paintable = info.entry.icon_paintable;
|
||||
|
||||
uint n_items = populate_permissions_list (permissions_list, info);
|
||||
|
||||
status_page.title = status_page.title = ngettext (
|
||||
"New Permission for %s",
|
||||
"New Permissions for %s",
|
||||
n_items
|
||||
).printf (info.entry.title);
|
||||
status_page.description = ngettext (
|
||||
"This update requires the following additional permission",
|
||||
"This update requires the following additional permissions",
|
||||
n_items
|
||||
);
|
||||
}
|
||||
|
||||
private void build_multi_layout (Gtk.Box box, Bz.UpdatePermissionInfo[] infos) {
|
||||
box.spacing = 24;
|
||||
foreach (var info in infos) {
|
||||
var entry = info.entry;
|
||||
|
||||
var app_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 8);
|
||||
|
||||
var header_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12) {
|
||||
valign = Gtk.Align.CENTER,
|
||||
margin_start = 8,
|
||||
};
|
||||
|
||||
if (entry.icon_paintable != null) {
|
||||
var icon = new Gtk.Image.from_paintable (entry.icon_paintable) {
|
||||
pixel_size = 48,
|
||||
};
|
||||
header_box.append (icon);
|
||||
}
|
||||
|
||||
var title_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 0) {
|
||||
valign = Gtk.Align.CENTER,
|
||||
};
|
||||
|
||||
var title_label = new Gtk.Label (entry.title) {
|
||||
halign = Gtk.Align.START,
|
||||
xalign = 0,
|
||||
};
|
||||
title_label.add_css_class ("heading");
|
||||
title_box.append (title_label);
|
||||
|
||||
if (entry.developer != null) {
|
||||
var developer_label = new Gtk.Label (entry.developer) {
|
||||
halign = Gtk.Align.START,
|
||||
xalign = 0,
|
||||
};
|
||||
developer_label.add_css_class ("dim-label");
|
||||
title_box.append (developer_label);
|
||||
}
|
||||
|
||||
header_box.append (title_box);
|
||||
|
||||
var permissions_list = new Gtk.ListBox () {
|
||||
selection_mode = Gtk.SelectionMode.NONE,
|
||||
};
|
||||
permissions_list.add_css_class ("boxed-list");
|
||||
populate_permissions_list (permissions_list, info);
|
||||
|
||||
app_box.append (header_box);
|
||||
app_box.append (permissions_list);
|
||||
|
||||
box.append (app_box);
|
||||
}
|
||||
}
|
||||
|
||||
private uint populate_permissions_list (Gtk.ListBox list, Bz.UpdatePermissionInfo info) {
|
||||
var permissions = info.additional_permissions;
|
||||
uint n_items = 0;
|
||||
|
||||
if (permissions != null) {
|
||||
var model = Bz.SafetyCalculator.analyze_permissions (permissions, false);
|
||||
n_items = model.get_n_items ();
|
||||
|
||||
for (int level = Bz.Importance.IMPORTANT; level >= Bz.Importance.UNIMPORTANT; level--) {
|
||||
for (uint j = 0; j < n_items; j++) {
|
||||
var row_data = (Bz.SafetyRow) model.get_item (j);
|
||||
|
||||
if (row_data.importance != level)
|
||||
continue;
|
||||
|
||||
var row = Bz.context_row_new (
|
||||
row_data.icon_name,
|
||||
row_data.importance,
|
||||
row_data.title,
|
||||
row_data.subtitle
|
||||
);
|
||||
list.append (row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n_items;
|
||||
}
|
||||
|
||||
public static Dex.Future present_and_wait (Gtk.Widget parent, Bz.UpdatePermissionInfo[] infos) {
|
||||
var dialog = new NewPermissionsDialog (infos);
|
||||
dialog.present (parent);
|
||||
return dialog.promise;
|
||||
}
|
||||
}
|
||||
11
src/bz-update-info.txt
Normal file
11
src/bz-update-info.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
prefix=bz
|
||||
name=update_permission_info
|
||||
parent-prefix=g
|
||||
parent-name=object
|
||||
author=AUTOGEN
|
||||
|
||||
include="bz-entry.h"
|
||||
include="bz-app-permissions.h"
|
||||
|
||||
property=entry BzEntry BZ_TYPE_ENTRY object
|
||||
property=additional_permissions BzAppPermissions BZ_TYPE_APP_PERMISSIONS object
|
||||
|
|
@ -33,8 +33,3 @@ template $BzUpdatesCard: Adw.Bin {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
FilterListModel runtimes_filter_model {
|
||||
filter: CustomFilter runtimes_filter {};
|
||||
model: bind template.state as <$BzStateInfo>.available-updates;
|
||||
}
|
||||
|
|
@ -1,505 +0,0 @@
|
|||
/* bz-updates-card.c
|
||||
*
|
||||
* Copyright 2026 Alexander Vanhee
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "bz-entry.h"
|
||||
#include "bz-release.h"
|
||||
#include "bz-releases-list.h"
|
||||
#include "bz-updates-card.h"
|
||||
#include "template-callbacks.h"
|
||||
|
||||
struct _BzUpdatesCard
|
||||
{
|
||||
AdwBin parent_instance;
|
||||
|
||||
BzStateInfo *state;
|
||||
|
||||
/* Template widgets */
|
||||
AdwExpanderRow *expander_row;
|
||||
GtkCustomFilter *runtimes_filter;
|
||||
GtkFilterListModel *runtimes_filter_model;
|
||||
|
||||
GPtrArray *app_rows;
|
||||
GtkWidget *runtimes_row;
|
||||
|
||||
gboolean has_closed;
|
||||
};
|
||||
|
||||
G_DEFINE_FINAL_TYPE (BzUpdatesCard, bz_updates_card, ADW_TYPE_BIN)
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_STATE,
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *props[LAST_PROP] = { 0 };
|
||||
|
||||
enum
|
||||
{
|
||||
SIGNAL_UPDATE,
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
static char *format_update_count (gpointer object, GListModel *updates);
|
||||
static void update_all_cb (GtkButton *button, BzUpdatesCard *self);
|
||||
static void update_runtimes_cb (GtkButton *button, BzUpdatesCard *self);
|
||||
static void on_expander_expanded_cb (AdwExpanderRow *row, GParamSpec *pspec, BzUpdatesCard *self);
|
||||
static gboolean filter_runtimes (BzEntry *entry, BzUpdatesCard *self);
|
||||
static void on_available_updates_changed (BzUpdatesCard *self, GParamSpec *pspec, BzStateInfo *state);
|
||||
static void on_runtimes_changed (GtkFilterListModel *model, guint position, guint removed, guint added, BzUpdatesCard *self);
|
||||
|
||||
static void
|
||||
on_update_single_cb (GtkButton *button,
|
||||
BzEntry *entry)
|
||||
{
|
||||
BzUpdatesCard *self = NULL;
|
||||
g_autoptr (GListStore) store = NULL;
|
||||
|
||||
self = BZ_UPDATES_CARD (gtk_widget_get_ancestor (GTK_WIDGET (button), BZ_TYPE_UPDATES_CARD));
|
||||
store = g_list_store_new (BZ_TYPE_ENTRY);
|
||||
g_list_store_append (store, entry);
|
||||
g_signal_emit (self, signals[SIGNAL_UPDATE], 0, store);
|
||||
}
|
||||
|
||||
static void
|
||||
on_version_history_cb (GtkButton *button,
|
||||
BzEntry *entry)
|
||||
{
|
||||
GtkRoot *root = NULL;
|
||||
g_autoptr (GListModel) history = NULL;
|
||||
GtkWidget *dialog = NULL;
|
||||
|
||||
root = gtk_widget_get_root (GTK_WIDGET (button));
|
||||
if (root == NULL)
|
||||
return;
|
||||
|
||||
g_object_get (entry, "version-history", &history, NULL);
|
||||
dialog = bz_releases_dialog_new (history, NULL);
|
||||
adw_dialog_present (ADW_DIALOG (dialog), GTK_WIDGET (root));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
build_app_row (BzEntry *entry,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
AdwActionRow *row = NULL;
|
||||
GtkWidget *icon = NULL;
|
||||
GtkWidget *history_button = NULL;
|
||||
GtkWidget *update_button = NULL;
|
||||
GdkPaintable *paintable = NULL;
|
||||
g_autoptr (GListModel) history = NULL;
|
||||
g_autofree char *installed_ver = NULL;
|
||||
const char *new_ver = NULL; // This will probably the same as the installed version if using cache...
|
||||
g_autofree char *subtitle = NULL;
|
||||
|
||||
row = ADW_ACTION_ROW (adw_action_row_new ());
|
||||
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (row),
|
||||
bz_entry_get_title (entry));
|
||||
|
||||
g_object_get (entry, "icon-paintable", &paintable, NULL);
|
||||
icon = paintable != NULL
|
||||
? gtk_image_new_from_paintable (paintable)
|
||||
: gtk_image_new_from_icon_name ("application-x-executable");
|
||||
g_clear_object (&paintable);
|
||||
|
||||
gtk_image_set_pixel_size (GTK_IMAGE (icon), 48);
|
||||
gtk_widget_set_size_request (icon, 48, 48);
|
||||
gtk_widget_set_margin_top (icon, 6);
|
||||
gtk_widget_set_margin_bottom (icon, 6);
|
||||
gtk_widget_set_valign (icon, GTK_ALIGN_CENTER);
|
||||
gtk_widget_add_css_class (icon, "icon-dropshadow");
|
||||
adw_action_row_add_prefix (row, icon);
|
||||
|
||||
g_object_get (entry,
|
||||
"version-history", &history,
|
||||
"installed-version", &installed_ver,
|
||||
NULL);
|
||||
|
||||
if (history != NULL && g_list_model_get_n_items (history) > 0 && installed_ver != NULL)
|
||||
{
|
||||
g_autoptr (BzRelease) first = g_list_model_get_item (history, 0);
|
||||
new_ver = bz_release_get_version (first);
|
||||
|
||||
if (new_ver != NULL)
|
||||
{
|
||||
if (g_strcmp0 (installed_ver, new_ver) != 0)
|
||||
subtitle = g_strdup_printf ("%s → %s", installed_ver, new_ver);
|
||||
else
|
||||
subtitle = g_strdup (new_ver);
|
||||
adw_action_row_set_subtitle (row, subtitle);
|
||||
}
|
||||
}
|
||||
|
||||
history_button = gtk_button_new_from_icon_name ("view-list-bullet-symbolic");
|
||||
gtk_widget_set_valign (history_button, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_tooltip_text (history_button, _ ("Version History"));
|
||||
gtk_widget_add_css_class (history_button, "flat");
|
||||
gtk_widget_set_visible (history_button, history != NULL && g_list_model_get_n_items (history) > 0);
|
||||
g_signal_connect_data (history_button, "clicked",
|
||||
G_CALLBACK (on_version_history_cb),
|
||||
g_object_ref (entry), (GClosureNotify) g_object_unref,
|
||||
0);
|
||||
adw_action_row_add_suffix (row, history_button);
|
||||
|
||||
update_button = gtk_button_new_with_label (_ ("Update"));
|
||||
gtk_widget_set_valign (update_button, GTK_ALIGN_CENTER);
|
||||
g_signal_connect_data (update_button, "clicked",
|
||||
G_CALLBACK (on_update_single_cb),
|
||||
g_object_ref (entry), (GClosureNotify) g_object_unref,
|
||||
0);
|
||||
adw_action_row_add_suffix (row, update_button);
|
||||
return GTK_WIDGET (row);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
build_runtimes_row (BzUpdatesCard *self)
|
||||
{
|
||||
AdwActionRow *row = NULL;
|
||||
GtkWidget *update_button = NULL;
|
||||
|
||||
row = ADW_ACTION_ROW (adw_action_row_new ());
|
||||
gtk_widget_set_visible (GTK_WIDGET (row), FALSE);
|
||||
|
||||
update_button = gtk_button_new_with_label (_ ("Update"));
|
||||
gtk_widget_set_valign (update_button, GTK_ALIGN_CENTER);
|
||||
g_signal_connect (update_button, "clicked",
|
||||
G_CALLBACK (update_runtimes_cb), self);
|
||||
adw_action_row_add_suffix (row, update_button);
|
||||
|
||||
return GTK_WIDGET (row);
|
||||
}
|
||||
|
||||
static void
|
||||
on_runtimes_changed (GtkFilterListModel *model,
|
||||
guint position,
|
||||
guint removed,
|
||||
guint added,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
guint n_items = 0;
|
||||
g_autofree char *title = NULL;
|
||||
|
||||
if (self->runtimes_row == NULL)
|
||||
return;
|
||||
|
||||
n_items = g_list_model_get_n_items (G_LIST_MODEL (model));
|
||||
gtk_widget_set_visible (self->runtimes_row, n_items > 0);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
title = g_strdup_printf (ngettext ("%u Runtime Update", "%u Runtime Updates", n_items), n_items);
|
||||
adw_preferences_row_set_title (ADW_PREFERENCES_ROW (self->runtimes_row), title);
|
||||
}
|
||||
|
||||
static void
|
||||
repopulate_expander_row (BzUpdatesCard *self)
|
||||
{
|
||||
GListModel *updates = NULL;
|
||||
guint n_items = 0;
|
||||
guint i = 0;
|
||||
|
||||
for (i = 0; i < self->app_rows->len; i++)
|
||||
adw_expander_row_remove (self->expander_row, g_ptr_array_index (self->app_rows, i));
|
||||
g_ptr_array_set_size (self->app_rows, 0);
|
||||
|
||||
if (self->runtimes_row != NULL)
|
||||
{
|
||||
adw_expander_row_remove (self->expander_row, self->runtimes_row);
|
||||
self->runtimes_row = NULL;
|
||||
}
|
||||
|
||||
if (self->state == NULL)
|
||||
return;
|
||||
|
||||
updates = bz_state_info_get_available_updates (self->state);
|
||||
if (updates == NULL)
|
||||
return;
|
||||
|
||||
n_items = g_list_model_get_n_items (updates);
|
||||
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr (BzEntry) entry = NULL;
|
||||
GtkWidget *row = NULL;
|
||||
|
||||
entry = g_list_model_get_item (updates, i);
|
||||
|
||||
if (entry == NULL || !BZ_IS_ENTRY (entry))
|
||||
continue;
|
||||
|
||||
if (!bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_APPLICATION))
|
||||
continue;
|
||||
|
||||
row = build_app_row (entry, self);
|
||||
adw_expander_row_add_row (self->expander_row, row);
|
||||
g_ptr_array_add (self->app_rows, row);
|
||||
}
|
||||
|
||||
self->runtimes_row = build_runtimes_row (self);
|
||||
adw_expander_row_add_row (self->expander_row, self->runtimes_row);
|
||||
on_runtimes_changed (self->runtimes_filter_model, 0, 0, 0, self);
|
||||
|
||||
if (!self->has_closed)
|
||||
adw_expander_row_set_expanded (self->expander_row, n_items <= 3);
|
||||
}
|
||||
|
||||
static void
|
||||
on_available_updates_changed (BzUpdatesCard *self,
|
||||
GParamSpec *pspec,
|
||||
BzStateInfo *state)
|
||||
{
|
||||
gtk_filter_changed (GTK_FILTER (self->runtimes_filter),
|
||||
GTK_FILTER_CHANGE_DIFFERENT);
|
||||
repopulate_expander_row (self);
|
||||
}
|
||||
|
||||
static void
|
||||
bz_updates_card_dispose (GObject *object)
|
||||
{
|
||||
BzUpdatesCard *self = BZ_UPDATES_CARD (object);
|
||||
|
||||
g_clear_object (&self->state);
|
||||
g_clear_pointer (&self->app_rows, g_ptr_array_unref);
|
||||
gtk_widget_dispose_template (GTK_WIDGET (self), BZ_TYPE_UPDATES_CARD);
|
||||
|
||||
G_OBJECT_CLASS (bz_updates_card_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
bz_updates_card_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BzUpdatesCard *self = BZ_UPDATES_CARD (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STATE:
|
||||
g_value_set_object (value, bz_updates_card_get_state (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bz_updates_card_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
BzUpdatesCard *self = BZ_UPDATES_CARD (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_STATE:
|
||||
bz_updates_card_set_state (self, g_value_get_object (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bz_updates_card_class_init (BzUpdatesCardClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
||||
|
||||
object_class->dispose = bz_updates_card_dispose;
|
||||
object_class->get_property = bz_updates_card_get_property;
|
||||
object_class->set_property = bz_updates_card_set_property;
|
||||
|
||||
props[PROP_STATE] =
|
||||
g_param_spec_object (
|
||||
"state",
|
||||
NULL, NULL,
|
||||
BZ_TYPE_STATE_INFO,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, LAST_PROP, props);
|
||||
|
||||
signals[SIGNAL_UPDATE] =
|
||||
g_signal_new (
|
||||
"update",
|
||||
G_OBJECT_CLASS_TYPE (klass),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_LIST_MODEL);
|
||||
g_signal_set_va_marshaller (
|
||||
signals[SIGNAL_UPDATE],
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
g_cclosure_marshal_VOID__OBJECTv);
|
||||
|
||||
gtk_widget_class_set_template_from_resource (widget_class, "/io/github/kolunmi/Bazaar/bz-updates-card.ui");
|
||||
|
||||
bz_widget_class_bind_all_util_callbacks (widget_class);
|
||||
gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, expander_row);
|
||||
gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, runtimes_filter);
|
||||
gtk_widget_class_bind_template_child (widget_class, BzUpdatesCard, runtimes_filter_model);
|
||||
gtk_widget_class_bind_template_callback (widget_class, format_update_count);
|
||||
gtk_widget_class_bind_template_callback (widget_class, update_all_cb);
|
||||
gtk_widget_class_bind_template_callback (widget_class, on_expander_expanded_cb);
|
||||
}
|
||||
|
||||
static void
|
||||
bz_updates_card_init (BzUpdatesCard *self)
|
||||
{
|
||||
gtk_widget_init_template (GTK_WIDGET (self));
|
||||
|
||||
self->app_rows = g_ptr_array_new ();
|
||||
|
||||
gtk_custom_filter_set_filter_func (
|
||||
self->runtimes_filter, (GtkCustomFilterFunc) filter_runtimes,
|
||||
self, NULL);
|
||||
|
||||
g_signal_connect (self->runtimes_filter_model, "items-changed",
|
||||
G_CALLBACK (on_runtimes_changed), self);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
bz_updates_card_new (void)
|
||||
{
|
||||
return g_object_new (BZ_TYPE_UPDATES_CARD, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
bz_updates_card_set_state (BzUpdatesCard *self,
|
||||
BzStateInfo *state)
|
||||
{
|
||||
g_return_if_fail (BZ_IS_UPDATES_CARD (self));
|
||||
g_return_if_fail (state == NULL || BZ_IS_STATE_INFO (state));
|
||||
|
||||
g_clear_object (&self->state);
|
||||
if (state != NULL)
|
||||
{
|
||||
self->state = g_object_ref (state);
|
||||
g_signal_connect_object (state, "notify::available-updates",
|
||||
G_CALLBACK (on_available_updates_changed),
|
||||
self, G_CONNECT_SWAPPED);
|
||||
}
|
||||
|
||||
gtk_filter_changed (GTK_FILTER (self->runtimes_filter),
|
||||
GTK_FILTER_CHANGE_DIFFERENT);
|
||||
|
||||
repopulate_expander_row (self);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), props[PROP_STATE]);
|
||||
}
|
||||
|
||||
BzStateInfo *
|
||||
bz_updates_card_get_state (BzUpdatesCard *self)
|
||||
{
|
||||
g_return_val_if_fail (BZ_IS_UPDATES_CARD (self), NULL);
|
||||
return self->state;
|
||||
}
|
||||
|
||||
static char *
|
||||
format_update_count (gpointer object,
|
||||
GListModel *updates)
|
||||
{
|
||||
guint n_updates = 0;
|
||||
|
||||
if (updates == NULL)
|
||||
return g_strdup ("");
|
||||
|
||||
n_updates = g_list_model_get_n_items (updates);
|
||||
|
||||
return g_strdup_printf (ngettext ("%u Available Update",
|
||||
"%u Available Updates",
|
||||
n_updates),
|
||||
n_updates);
|
||||
}
|
||||
|
||||
static void
|
||||
update_all_cb (GtkButton *button,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
GListModel *updates = NULL;
|
||||
|
||||
g_return_if_fail (GTK_IS_BUTTON (button));
|
||||
g_return_if_fail (BZ_IS_UPDATES_CARD (self));
|
||||
|
||||
if (self->state == NULL)
|
||||
return;
|
||||
|
||||
updates = bz_state_info_get_available_updates (self->state);
|
||||
if (updates == NULL)
|
||||
return;
|
||||
|
||||
g_signal_emit (self, signals[SIGNAL_UPDATE], 0, updates);
|
||||
}
|
||||
|
||||
static void
|
||||
update_runtimes_cb (GtkButton *button,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
GListModel *runtimes = NULL;
|
||||
g_autoptr (GListStore) store = NULL;
|
||||
guint n_items = 0;
|
||||
|
||||
runtimes = G_LIST_MODEL (self->runtimes_filter_model);
|
||||
n_items = g_list_model_get_n_items (runtimes);
|
||||
|
||||
if (n_items == 0)
|
||||
return;
|
||||
|
||||
store = g_list_store_new (BZ_TYPE_ENTRY);
|
||||
|
||||
for (guint i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr (BzEntry) entry = g_list_model_get_item (runtimes, i);
|
||||
if (entry != NULL)
|
||||
g_list_store_append (store, entry);
|
||||
}
|
||||
|
||||
g_signal_emit (self, signals[SIGNAL_UPDATE], 0, store);
|
||||
}
|
||||
|
||||
static void
|
||||
on_expander_expanded_cb (AdwExpanderRow *row,
|
||||
GParamSpec *pspec,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
if (!adw_expander_row_get_expanded (row))
|
||||
self->has_closed = TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
filter_runtimes (BzEntry *entry,
|
||||
BzUpdatesCard *self)
|
||||
{
|
||||
g_return_val_if_fail (BZ_IS_ENTRY (entry), FALSE);
|
||||
|
||||
return bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_RUNTIME) ||
|
||||
bz_entry_is_of_kinds (entry, BZ_ENTRY_KIND_ADDON);
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
/* bz-updates-card.h
|
||||
*
|
||||
* Copyright 2026 Alexander Vanhee
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "bz-state-info.h"
|
||||
#include <adwaita.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define BZ_TYPE_UPDATES_CARD (bz_updates_card_get_type ())
|
||||
|
||||
G_DECLARE_FINAL_TYPE (BzUpdatesCard, bz_updates_card, BZ, UPDATES_CARD, AdwBin)
|
||||
|
||||
GtkWidget *
|
||||
bz_updates_card_new (void);
|
||||
|
||||
void
|
||||
bz_updates_card_set_state (BzUpdatesCard *self,
|
||||
BzStateInfo *state);
|
||||
|
||||
BzStateInfo *
|
||||
bz_updates_card_get_state (BzUpdatesCard *self);
|
||||
|
||||
G_END_DECLS
|
||||
213
src/bz-updates-card.vala
Normal file
213
src/bz-updates-card.vala
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/* bz-updates-card.vala
|
||||
*
|
||||
* Copyright 2026 Alexander Vanhee
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
[GtkTemplate (ui = "/io/github/kolunmi/Bazaar/bz-updates-card.ui")]
|
||||
public class Bz.UpdatesCard : Adw.Bin {
|
||||
private Bz.StateInfo? _state;
|
||||
public Bz.StateInfo? state {
|
||||
get { return _state; }
|
||||
set {
|
||||
_state = value;
|
||||
if (_state != null)
|
||||
_state.notify["available-updates"].connect ((s, p) => repopulate ());
|
||||
|
||||
repopulate ();
|
||||
}
|
||||
}
|
||||
|
||||
[GtkChild]
|
||||
private unowned Adw.ExpanderRow expander_row;
|
||||
|
||||
private GenericArray<Gtk.Widget> app_rows = new GenericArray<Gtk.Widget> ();
|
||||
private Gtk.Widget? runtimes_row = null;
|
||||
private GenericArray<Bz.Entry> runtime_entries = new GenericArray<Bz.Entry> ();
|
||||
private bool has_closed = false;
|
||||
|
||||
public signal void update (ListModel entries);
|
||||
|
||||
[GtkCallback]
|
||||
private string format_update_count (ListModel? updates) {
|
||||
if (updates == null)
|
||||
return "";
|
||||
|
||||
uint n_updates = updates.get_n_items ();
|
||||
return ngettext ("%u Available Update", "%u Available Updates", n_updates).printf (n_updates);
|
||||
}
|
||||
|
||||
[GtkCallback]
|
||||
private void update_all_cb (Gtk.Button button) {
|
||||
var updates = _state?.available_updates;
|
||||
if (updates == null || updates.get_n_items () == 0)
|
||||
return;
|
||||
|
||||
var entries = new GenericArray<Bz.Entry> ();
|
||||
uint n_items = updates.get_n_items ();
|
||||
for (uint i = 0; i < n_items; i++) {
|
||||
var entry = (updates.get_item (i) as Bz.UpdatePermissionInfo)?.entry;
|
||||
if (entry != null)
|
||||
entries.add (entry);
|
||||
}
|
||||
emit_update (entries);
|
||||
}
|
||||
|
||||
[GtkCallback]
|
||||
private void on_expander_expanded_cb (Object row, ParamSpec pspec) {
|
||||
if (!expander_row.expanded)
|
||||
has_closed = true;
|
||||
}
|
||||
|
||||
private void emit_update (GenericArray<Bz.Entry> entries) {
|
||||
var store = new ListStore (typeof (Bz.Entry));
|
||||
foreach (var entry in entries)
|
||||
store.append (entry);
|
||||
update (store);
|
||||
}
|
||||
|
||||
private void repopulate () {
|
||||
foreach (var row in app_rows)
|
||||
expander_row.remove (row);
|
||||
if (runtimes_row != null)
|
||||
expander_row.remove (runtimes_row);
|
||||
|
||||
app_rows = new GenericArray<Gtk.Widget> ();
|
||||
runtime_entries = new GenericArray<Bz.Entry> ();
|
||||
runtimes_row = null;
|
||||
|
||||
var updates = _state?.available_updates;
|
||||
if (updates == null)
|
||||
return;
|
||||
|
||||
uint n_items = updates.get_n_items ();
|
||||
|
||||
for (uint i = 0; i < n_items; i++) {
|
||||
var info = updates.get_item (i) as Bz.UpdatePermissionInfo;
|
||||
var entry = info?.entry;
|
||||
if (entry == null)
|
||||
continue;
|
||||
|
||||
if (entry.is_of_kinds (Bz.EntryKind.APPLICATION)) {
|
||||
var row = build_app_row (info);
|
||||
expander_row.add_row (row);
|
||||
app_rows.add (row);
|
||||
} else if (entry.is_of_kinds (Bz.EntryKind.RUNTIME) ||
|
||||
entry.is_of_kinds (Bz.EntryKind.ADDON)) {
|
||||
runtime_entries.add (entry);
|
||||
}
|
||||
}
|
||||
|
||||
runtimes_row = build_runtimes_row ();
|
||||
expander_row.add_row (runtimes_row);
|
||||
|
||||
if (!has_closed)
|
||||
expander_row.expanded = n_items <= 3;
|
||||
}
|
||||
|
||||
private Gtk.Widget build_app_row (Bz.UpdatePermissionInfo info) {
|
||||
var entry = info.entry;
|
||||
var delta = info.additional_permissions;
|
||||
|
||||
var row = new Adw.ActionRow () {
|
||||
title = entry.title,
|
||||
};
|
||||
|
||||
var icon = new Gtk.Image () {
|
||||
pixel_size = 48,
|
||||
valign = Gtk.Align.CENTER,
|
||||
margin_top = 6,
|
||||
margin_bottom = 6,
|
||||
};
|
||||
if (entry.icon_paintable != null)
|
||||
icon.paintable = entry.icon_paintable;
|
||||
else
|
||||
icon.icon_name = "application-x-executable";
|
||||
icon.add_css_class ("icon-dropshadow");
|
||||
row.add_prefix (icon);
|
||||
|
||||
ListModel? history = entry.version_history;
|
||||
string? installed_ver = entry.installed_version;
|
||||
bool has_history = history != null && history.get_n_items () > 0;
|
||||
|
||||
if (has_history && installed_ver != null) {
|
||||
string? new_ver = ((Bz.Release) history.get_item (0)).version;
|
||||
|
||||
if (new_ver != null)
|
||||
row.subtitle = installed_ver != new_ver
|
||||
? "%s → %s".printf (installed_ver, new_ver)
|
||||
: new_ver;
|
||||
}
|
||||
|
||||
if (delta != null && !delta.is_empty ()) {
|
||||
var permissions_icon = new Gtk.Image.from_icon_name ("permissions-warning-symbolic") {
|
||||
valign = Gtk.Align.CENTER,
|
||||
tooltip_text = _("This update requests new permissions"),
|
||||
};
|
||||
permissions_icon.add_css_class ("warning");
|
||||
row.add_suffix (permissions_icon);
|
||||
}
|
||||
|
||||
var history_button = new Gtk.Button.from_icon_name ("view-list-bullet-symbolic") {
|
||||
valign = Gtk.Align.CENTER,
|
||||
tooltip_text = _("Version History"),
|
||||
visible = has_history,
|
||||
};
|
||||
history_button.add_css_class ("flat");
|
||||
history_button.clicked.connect (() => {
|
||||
var dialog = Bz.ReleasesList.dialog_new (entry.version_history, null);
|
||||
((Adw.Dialog) dialog).present (this.get_root ());
|
||||
});
|
||||
|
||||
row.add_suffix (history_button);
|
||||
|
||||
var update_button = new Gtk.Button.with_label (_("Update")) {
|
||||
valign = Gtk.Align.CENTER,
|
||||
};
|
||||
update_button.clicked.connect (() => {
|
||||
var entries = new GenericArray<Bz.Entry> ();
|
||||
entries.add (info.entry);
|
||||
emit_update (entries);
|
||||
});
|
||||
row.add_suffix (update_button);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
private Gtk.Widget build_runtimes_row () {
|
||||
uint n_items = runtime_entries.length;
|
||||
|
||||
var row = new Adw.ActionRow () {
|
||||
visible = n_items > 0,
|
||||
};
|
||||
|
||||
if (n_items > 0)
|
||||
row.title = ngettext ("%u Runtime Update", "%u Runtime Updates", n_items).printf (n_items);
|
||||
|
||||
var update_button = new Gtk.Button.with_label (_("Update")) {
|
||||
valign = Gtk.Align.CENTER,
|
||||
};
|
||||
update_button.clicked.connect (() => {
|
||||
if (runtime_entries.length == 0)
|
||||
return;
|
||||
emit_update (runtime_entries);
|
||||
});
|
||||
row.add_suffix (update_button);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
148
src/bz-window.c
148
src/bz-window.c
|
|
@ -21,8 +21,8 @@
|
|||
// This file is an utter mess
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <bzvala.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "bz-addons-dialog.h"
|
||||
#include "bz-application.h"
|
||||
|
|
@ -42,6 +42,7 @@
|
|||
#include "bz-transaction-manager.h"
|
||||
#include "bz-update-history-data-point.h"
|
||||
#include "bz-update-history-dialog.h"
|
||||
#include "bz-update-info.h"
|
||||
#include "bz-user-data-page.h"
|
||||
#include "bz-window.h"
|
||||
#include "env.h"
|
||||
|
|
@ -103,6 +104,10 @@ BZ_DEFINE_DATA (
|
|||
BZ_RELEASE_DATA (group, g_object_unref);
|
||||
BZ_RELEASE_DATA (source, g_object_unref))
|
||||
|
||||
static DexFuture *
|
||||
update_fiber (BzWeakRef *wr,
|
||||
GListModel *entries);
|
||||
|
||||
static DexFuture *
|
||||
transact_fiber (TransactData *data);
|
||||
|
||||
|
|
@ -215,68 +220,119 @@ update_cb (BzWindow *self,
|
|||
GListModel *entries,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
g_autoptr (BzTransaction) transaction = NULL;
|
||||
guint n_updates = 0;
|
||||
g_autofree BzEntry **updates_buf = NULL;
|
||||
GListModel *available_updates = NULL;
|
||||
g_autoptr (BzWeakRef) wr = NULL;
|
||||
|
||||
g_return_if_fail (BZ_IS_WINDOW (self));
|
||||
g_return_if_fail (G_IS_LIST_MODEL (entries));
|
||||
|
||||
n_updates = g_list_model_get_n_items (entries);
|
||||
if (n_updates == 0)
|
||||
if (g_list_model_get_n_items (entries) == 0)
|
||||
return;
|
||||
|
||||
updates_buf = g_malloc_n (n_updates, sizeof (*updates_buf));
|
||||
for (guint i = 0; i < n_updates; i++)
|
||||
updates_buf[i] = g_list_model_get_item (entries, i);
|
||||
wr = bz_weak_ref_new (self);
|
||||
|
||||
transaction = bz_transaction_new_full (
|
||||
NULL, 0,
|
||||
updates_buf, n_updates,
|
||||
NULL, 0);
|
||||
dex_future_disown (dex_scheduler_spawnv (
|
||||
dex_scheduler_get_default (), bz_get_dex_stack_size (),
|
||||
G_CALLBACK (update_fiber),
|
||||
2, BZ_TYPE_WEAK_REF, wr, G_TYPE_OBJECT, entries));
|
||||
}
|
||||
|
||||
static DexFuture *
|
||||
update_fiber (BzWeakRef *wr,
|
||||
GListModel *entries)
|
||||
{
|
||||
g_autoptr (BzWindow) self = NULL;
|
||||
g_autoptr (BzTransaction) transaction = NULL;
|
||||
g_autoptr (GPtrArray) updates = NULL;
|
||||
g_autoptr (GHashTable) update_ids = NULL;
|
||||
GListModel *available_updates = NULL;
|
||||
g_autoptr (GPtrArray) permission_infos = NULL;
|
||||
guint n_updates = 0;
|
||||
|
||||
bz_weak_get_or_return_reject (self, &wr->ref);
|
||||
|
||||
n_updates = g_list_model_get_n_items (entries);
|
||||
updates = g_ptr_array_new_full (n_updates, g_object_unref);
|
||||
update_ids = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
for (guint i = 0; i < n_updates; i++)
|
||||
{
|
||||
BzEntry *entry = NULL;
|
||||
|
||||
entry = g_list_model_get_item (entries, i);
|
||||
g_ptr_array_add (updates, entry);
|
||||
g_hash_table_add (update_ids, (gpointer) bz_entry_get_id (entry));
|
||||
}
|
||||
|
||||
available_updates = bz_state_info_get_available_updates (self->state);
|
||||
|
||||
permission_infos = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
if (available_updates != NULL)
|
||||
{
|
||||
guint n_available = 0;
|
||||
|
||||
n_available = g_list_model_get_n_items (available_updates);
|
||||
|
||||
for (guint i = 0; i < n_available; i++)
|
||||
{
|
||||
g_autoptr (BzUpdatePermissionInfo) info = NULL;
|
||||
BzEntry *info_entry = NULL;
|
||||
const char *info_id = NULL;
|
||||
BzAppPermissions *delta = NULL;
|
||||
|
||||
info = g_list_model_get_item (available_updates, i);
|
||||
info_entry = bz_update_permission_info_get_entry (info);
|
||||
info_id = bz_entry_get_id (info_entry);
|
||||
delta = bz_update_permission_info_get_additional_permissions (info);
|
||||
|
||||
if (delta == NULL || bz_app_permissions_is_empty (delta))
|
||||
continue;
|
||||
|
||||
if (g_hash_table_contains (update_ids, info_id))
|
||||
g_ptr_array_add (permission_infos, g_object_ref (info));
|
||||
}
|
||||
}
|
||||
|
||||
if (permission_infos->len > 0)
|
||||
{
|
||||
gboolean confirmed = FALSE;
|
||||
|
||||
confirmed = dex_await_boolean (
|
||||
bz_new_permissions_dialog_present_and_wait (
|
||||
GTK_WIDGET (self),
|
||||
(BzUpdatePermissionInfo **) permission_infos->pdata,
|
||||
permission_infos->len),
|
||||
NULL);
|
||||
|
||||
if (!confirmed)
|
||||
return dex_future_new_false ();
|
||||
}
|
||||
|
||||
transaction = bz_transaction_new_full (NULL, 0, (BzEntry **) updates->pdata,
|
||||
updates->len, NULL, 0);
|
||||
|
||||
dex_future_disown (bz_transaction_manager_add (
|
||||
bz_state_info_get_transaction_manager (self->state),
|
||||
transaction));
|
||||
|
||||
available_updates = bz_state_info_get_available_updates (self->state);
|
||||
if (G_IS_LIST_STORE (available_updates))
|
||||
{
|
||||
GListStore *store = G_LIST_STORE (available_updates);
|
||||
guint n_available = g_list_model_get_n_items (available_updates);
|
||||
GListStore *store = NULL;
|
||||
guint n_available = 0;
|
||||
|
||||
store = G_LIST_STORE (available_updates);
|
||||
n_available = g_list_model_get_n_items (available_updates);
|
||||
|
||||
for (guint i = n_available; i > 0; i--)
|
||||
{
|
||||
guint current_size = 0;
|
||||
guint idx = 0;
|
||||
g_autoptr (BzEntry) available_entry = NULL;
|
||||
const char *available_id = NULL;
|
||||
g_autoptr (BzUpdatePermissionInfo) available_info = NULL;
|
||||
const char *available_id = NULL;
|
||||
|
||||
idx = i - 1;
|
||||
current_size = g_list_model_get_n_items (available_updates);
|
||||
available_info = g_list_model_get_item (available_updates, i - 1);
|
||||
available_id = bz_entry_get_id (bz_update_permission_info_get_entry (available_info));
|
||||
|
||||
if (idx >= current_size)
|
||||
continue;
|
||||
|
||||
available_entry = g_list_model_get_item (available_updates, idx);
|
||||
available_id = bz_entry_get_id (available_entry);
|
||||
|
||||
for (guint j = 0; j < n_updates; j++)
|
||||
{
|
||||
if (g_strcmp0 (available_id, bz_entry_get_id (updates_buf[j])) == 0)
|
||||
{
|
||||
g_list_store_remove (store, idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (g_hash_table_contains (update_ids, available_id))
|
||||
g_list_store_remove (store, i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_notify (G_OBJECT (self->state), "available-updates");
|
||||
|
||||
for (guint i = 0; i < n_updates; i++)
|
||||
g_object_unref (updates_buf[i]);
|
||||
return dex_future_new_true ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -785,7 +841,7 @@ open_uri_finish_cb (GObject *source,
|
|||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (BzWindow) self = BZ_WINDOW (user_data);
|
||||
GtkUriLauncher *launcher = GTK_URI_LAUNCHER (source);
|
||||
GtkUriLauncher *launcher = GTK_URI_LAUNCHER (source);
|
||||
g_autoptr (GError) local_error = NULL;
|
||||
|
||||
if (!gtk_uri_launcher_launch_finish (launcher, result, &local_error) &&
|
||||
|
|
@ -798,8 +854,8 @@ action_open_uri (GtkWidget *widget,
|
|||
const char *action_name,
|
||||
GVariant *parameter)
|
||||
{
|
||||
BzWindow *self = BZ_WINDOW (widget);
|
||||
const char *uri = g_variant_get_string (parameter, NULL);
|
||||
BzWindow *self = BZ_WINDOW (widget);
|
||||
const char *uri = g_variant_get_string (parameter, NULL);
|
||||
g_autoptr (GtkUriLauncher) launcher = NULL;
|
||||
|
||||
if (uri == NULL || *uri == '\0')
|
||||
|
|
|
|||
75
src/bz.vapi
75
src/bz.vapi
|
|
@ -47,6 +47,9 @@ public extern class Bz.AllAppsPage : GLib.Object {
|
|||
public extern class Bz.AppPermissions : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected AppPermissions ();
|
||||
|
||||
[CCode (cname = "bz_app_permissions_is_empty")]
|
||||
public bool is_empty ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-app-size-dialog.h", type_id = "bz_app_size_dialog_get_type ()")]
|
||||
|
|
@ -159,10 +162,10 @@ public extern class Bz.ContentProvider : GLib.Object {
|
|||
protected ContentProvider ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-context-row.h", type_id = "bz_context_row_get_type ()")]
|
||||
public extern class Bz.ContextRow : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected ContextRow ();
|
||||
[CCode (cheader_filename = "bz-context-row.h")]
|
||||
namespace Bz {
|
||||
[CCode (cname = "bz_context_row_new")]
|
||||
public unowned Adw.ActionRow context_row_new (string? icon_name, Bz.Importance importance, string title, string? subtitle);
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-context-tile.h", type_id = "bz_context_tile_get_type ()")]
|
||||
|
|
@ -239,6 +242,14 @@ public extern class Bz.EntryInspector : GLib.Object {
|
|||
protected EntryInspector ();
|
||||
}
|
||||
|
||||
[Flags]
|
||||
[CCode (cheader_filename = "bz-entry.h", cname = "BzEntryKind", cprefix = "BZ_ENTRY_KIND_", has_type_id = false)]
|
||||
public enum Bz.EntryKind {
|
||||
APPLICATION,
|
||||
RUNTIME,
|
||||
ADDON,
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-entry.h", type_id = "bz_entry_get_type ()")]
|
||||
public extern class Bz.Entry : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
|
|
@ -246,7 +257,16 @@ public extern class Bz.Entry : GLib.Object {
|
|||
|
||||
public string? unique_id { get; set; }
|
||||
|
||||
public string? title { get; }
|
||||
public string? developer { get; }
|
||||
public Gdk.Paintable? icon_paintable { get; }
|
||||
[NoAccessorMethod]
|
||||
public GLib.ListModel? version_history { owned get; }
|
||||
public string? installed_version { get; }
|
||||
public Bz.Repository? get_repository (GLib.ListModel repos);
|
||||
|
||||
[CCode (cname = "bz_entry_is_of_kinds")]
|
||||
public bool is_of_kinds (Bz.EntryKind kinds);
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-error-dialog.h", type_id = "bz_error_dialog_get_type ()")]
|
||||
|
|
@ -453,6 +473,9 @@ public extern class Bz.ProgressBar : GLib.Object {
|
|||
public extern class Bz.ReleasesList : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected ReleasesList ();
|
||||
|
||||
[CCode (cname = "bz_releases_dialog_new")]
|
||||
public static unowned Gtk.Widget dialog_new (GLib.ListModel? version_history, GLib.ListModel? installed_versions);
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-result.h", type_id = "bz_result_get_type ()")]
|
||||
|
|
@ -599,18 +622,21 @@ public extern class Bz.Transaction : GLib.Object {
|
|||
protected Transaction ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-update-info.h", type_id = "bz_update_permission_info_get_type ()")]
|
||||
public extern class Bz.UpdatePermissionInfo : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected UpdatePermissionInfo ();
|
||||
|
||||
public Bz.Entry? entry { get; set; }
|
||||
public Bz.AppPermissions? additional_permissions { get; set;}
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-update-history-dialog.h", type_id = "bz_update_history_dialog_get_type ()")]
|
||||
public extern class Bz.UpdateHistoryDialog : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected UpdateHistoryDialog ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-updates-card.h", type_id = "bz_updates_card_get_type ()")]
|
||||
public extern class Bz.UpdatesCard : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected UpdatesCard ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-user-data-page.h", type_id = "bz_user_data_page_get_type ()")]
|
||||
public extern class Bz.UserDataPage : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
|
|
@ -896,6 +922,8 @@ public extern class Bz.PrideFlagStripeSpec : GLib.Object {
|
|||
public extern class Bz.Release : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected Release ();
|
||||
|
||||
public string? version { get; set; }
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-repository.h", type_id = "bz_repository_get_type ()")]
|
||||
|
|
@ -922,10 +950,36 @@ public extern class Bz.RootCuratedConfig : GLib.Object {
|
|||
protected RootCuratedConfig ();
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "safety-calculator.h", cname = "BzImportance", cprefix = "BZ_IMPORTANCE_", has_type_id = false)]
|
||||
public enum Bz.Importance {
|
||||
UNIMPORTANT,
|
||||
NEUTRAL,
|
||||
INFORMATION,
|
||||
WARNING,
|
||||
IMPORTANT,
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "safety-calculator.h")]
|
||||
namespace Bz.SafetyCalculator {
|
||||
[CCode (cname = "bz_safety_calculator_analyze_permissions")]
|
||||
public static GLib.ListModel analyze_permissions (Bz.AppPermissions? permissions, bool include_no_access_rows);
|
||||
|
||||
[CCode (cname = "bz_safety_calculator_analyze_entry")]
|
||||
public GLib.ListModel analyze_entry (Bz.Entry entry);
|
||||
|
||||
[CCode (cname = "bz_safety_calculator_calculate_rating")]
|
||||
public Bz.Importance calculate_rating (Bz.Entry entry);
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-safety-row.h", type_id = "bz_safety_row_get_type ()")]
|
||||
public extern class Bz.SafetyRow : GLib.Object {
|
||||
[CCode (has_construct_function = false)]
|
||||
protected SafetyRow ();
|
||||
|
||||
public Bz.Importance importance { get; set;}
|
||||
public string? icon_name { get; set;}
|
||||
public string? title { get; set;}
|
||||
public string? subtitle { get; set;}
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-search-bias.h", type_id = "bz_search_bias_get_type ()")]
|
||||
|
|
@ -955,6 +1009,7 @@ public extern class Bz.StateInfo : GLib.Object {
|
|||
public static unowned Bz.StateInfo get_default ();
|
||||
|
||||
public GLib.ListModel? repositories { get; }
|
||||
public GLib.ListModel? available_updates { get; set; }
|
||||
}
|
||||
|
||||
[CCode (cheader_filename = "bz-transact-icon-info.h", type_id = "bz_transact_icon_info_get_type ()")]
|
||||
|
|
|
|||
|
|
@ -152,7 +152,6 @@ bz_sources = files(
|
|||
'bz-transaction-manager.c',
|
||||
'bz-transaction-tile.c',
|
||||
'bz-transaction.c',
|
||||
'bz-updates-card.c',
|
||||
'bz-update-history-dialog.c',
|
||||
'bz-user-data-page.c',
|
||||
'bz-user-data-tile.c',
|
||||
|
|
@ -264,6 +263,7 @@ gobject_specs = files(
|
|||
'bz-size-result.txt',
|
||||
'bz-state-info.txt',
|
||||
'bz-update-history-data-point.txt',
|
||||
'bz-update-info.txt',
|
||||
'bz-transact-icon-info.txt',
|
||||
'bz-transaction-dialog-result.txt',
|
||||
'bz-transaction-entry-tracker.txt',
|
||||
|
|
@ -407,8 +407,10 @@ vala_sources = files(
|
|||
'bz-cosmic-place-applet-dialog.vala',
|
||||
'bz-decorated-screenshot.vala',
|
||||
'bz-themed-rect.vala',
|
||||
'bz-updates-card.vala',
|
||||
'bz-flathub-curated-section.vala',
|
||||
'bz-other-sources-list.vala',
|
||||
'bz-new-permissions-dialog.vala',
|
||||
)
|
||||
|
||||
vala_args = [
|
||||
|
|
|
|||
|
|
@ -49,13 +49,11 @@ lookup_well_known_bus_policy (const char *bus_name,
|
|||
const char **out_description);
|
||||
|
||||
GListModel *
|
||||
bz_safety_calculator_analyze_entry (BzEntry *entry)
|
||||
bz_safety_calculator_analyze_permissions (BzAppPermissions *permissions,
|
||||
gboolean include_no_access_rows)
|
||||
{
|
||||
GListStore *store = NULL;
|
||||
BzAppPermissions *permissions = NULL;
|
||||
BzAppPermissionsFlags perm_flags = BZ_APP_PERMISSIONS_FLAGS_NONE;
|
||||
gboolean is_verified = FALSE;
|
||||
gboolean is_foss = FALSE;
|
||||
const GPtrArray *filesystem_read = NULL;
|
||||
const GPtrArray *filesystem_full = NULL;
|
||||
const BzBusPolicy *const *bus_policies = NULL;
|
||||
|
|
@ -64,13 +62,8 @@ bz_safety_calculator_analyze_entry (BzEntry *entry)
|
|||
BzImportance fs_importance = BZ_IMPORTANCE_WARNING;
|
||||
guint i = 0;
|
||||
|
||||
g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL);
|
||||
store = g_list_store_new (BZ_TYPE_SAFETY_ROW);
|
||||
|
||||
store = g_list_store_new (BZ_TYPE_SAFETY_ROW);
|
||||
is_verified = bz_entry_is_verified (entry);
|
||||
is_foss = bz_entry_get_is_foss (entry);
|
||||
|
||||
g_object_get (entry, "permissions", &permissions, NULL);
|
||||
if (permissions != NULL)
|
||||
perm_flags = bz_app_permissions_get_flags (permissions);
|
||||
|
||||
|
|
@ -87,264 +80,289 @@ bz_safety_calculator_analyze_entry (BzEntry *entry)
|
|||
_ ("Unknown Permissions"),
|
||||
_ ("Permissions are missing for this app."),
|
||||
NULL, NULL, NULL);
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
else
|
||||
|
||||
filesystem_read = bz_app_permissions_get_filesystem_read (permissions);
|
||||
filesystem_full = bz_app_permissions_get_filesystem_full (permissions);
|
||||
bus_policies = bz_app_permissions_get_bus_policies (permissions, &n_bus_policies);
|
||||
|
||||
if (include_no_access_rows)
|
||||
add_row_if_permission (store,
|
||||
bz_app_permissions_is_empty (permissions),
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"permissions-sandboxed-symbolic",
|
||||
_ ("No Permissions"),
|
||||
_ ("App is fully sandboxed"),
|
||||
NULL, NULL, NULL);
|
||||
if (include_no_access_rows)
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_NETWORK) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"network-wireless-symbolic",
|
||||
_ ("Network Access"),
|
||||
_ ("Can access the internet"),
|
||||
"network-wireless-disabled-symbolic",
|
||||
_ ("No Network Access"),
|
||||
_ ("Cannot access the internet"));
|
||||
|
||||
if ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DEVICES) || include_no_access_rows)
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_DEVICES) != 0,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_NETWORK) ? BZ_IMPORTANCE_WARNING : BZ_IMPORTANCE_INFORMATION,
|
||||
"camera-photo-symbolic",
|
||||
_ ("User Device Access"),
|
||||
_ ("Can access devices such as webcams or gaming controllers"),
|
||||
"camera-disabled-symbolic",
|
||||
_ ("No User Device Access"),
|
||||
_ ("Cannot access devices such as webcams or gaming controllers"));
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"input-keyboard-symbolic",
|
||||
_ ("Input Device Access"),
|
||||
_ ("Can access input devices"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"permissions-microphone-symbolic",
|
||||
_ ("Microphone Access and Audio Playback"),
|
||||
_ ("Can listen using microphones and play audio without asking permission"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"permissions-system-devices-symbolic",
|
||||
_ ("System Device Access"),
|
||||
_ ("Can access system devices which require elevated permissions"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SCREEN) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"permissions-screen-contents-symbolic",
|
||||
_ ("Screen Contents Access"),
|
||||
_ ("Can access the contents of the screen or other windows"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_X11) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"permissions-legacy-windowing-system-symbolic",
|
||||
_ ("Legacy Windowing System"),
|
||||
_ ("Always uses a legacy windowing system (X11)"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"earth-symbolic",
|
||||
_ ("Arbitrary Permissions"),
|
||||
_ ("Can acquire arbitrary permissions"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SETTINGS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("User Settings"),
|
||||
_ ("Can access and change user settings"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"drive-harddisk-symbolic",
|
||||
_ ("Full File System Read/Write Access"),
|
||||
_ ("Can read and write all data on the file system"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) != 0 &&
|
||||
!(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"user-home-symbolic",
|
||||
_ ("Home Folder Read/Write Access"),
|
||||
_ ("Can read and write all data in your home directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ) != 0 &&
|
||||
!(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"folder-symbolic",
|
||||
_ ("Full File System Read Access"),
|
||||
_ ("Can read all data on the file system"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_READ) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ))),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"user-home-symbolic",
|
||||
_ ("Home Folder Read Access"),
|
||||
_ ("Can read all data in your home directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL))),
|
||||
fs_importance,
|
||||
"folder-download-symbolic",
|
||||
_ ("Download Folder Read/Write Access"),
|
||||
_ ("Can read and write all data in your downloads directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ))),
|
||||
fs_importance,
|
||||
"folder-download-symbolic",
|
||||
_ ("Download Folder Read Access"),
|
||||
_ ("Can read all data in your downloads directory"),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
for (i = 0; filesystem_full != NULL && i < filesystem_full->len; i++)
|
||||
{
|
||||
filesystem_read = bz_app_permissions_get_filesystem_read (permissions);
|
||||
filesystem_full = bz_app_permissions_get_filesystem_full (permissions);
|
||||
bus_policies = bz_app_permissions_get_bus_policies (permissions, &n_bus_policies);
|
||||
const BzFilesystemPath *path = g_ptr_array_index (filesystem_full, i);
|
||||
g_autofree char *fs_title = bz_filesystem_path_to_display_string (path);
|
||||
const char *fs_icon = bz_filesystem_path_to_icon_name (path);
|
||||
|
||||
add_row_if_permission (store,
|
||||
bz_app_permissions_is_empty (permissions),
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"permissions-sandboxed-symbolic",
|
||||
_ ("No Permissions"),
|
||||
_ ("App is fully sandboxed"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_NETWORK) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"network-wireless-symbolic",
|
||||
_ ("Network Access"),
|
||||
_ ("Can access the internet"),
|
||||
"network-wireless-disabled-symbolic",
|
||||
_ ("No Network Access"),
|
||||
_ ("Cannot access the internet"));
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_DEVICES) != 0,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_NETWORK) ? BZ_IMPORTANCE_WARNING : BZ_IMPORTANCE_INFORMATION,
|
||||
"camera-photo-symbolic",
|
||||
_ ("User Device Access"),
|
||||
_ ("Can access devices such as webcams or gaming controllers"),
|
||||
"camera-disabled-symbolic",
|
||||
_ ("No User Device Access"),
|
||||
_ ("Cannot access devices such as webcams or gaming controllers"));
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_INPUT_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"input-keyboard-symbolic",
|
||||
_ ("Input Device Access"),
|
||||
_ ("Can access input devices"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_AUDIO_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_INFORMATION,
|
||||
"permissions-microphone-symbolic",
|
||||
_ ("Microphone Access and Audio Playback"),
|
||||
_ ("Can listen using microphones and play audio without asking permission"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_DEVICES) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"permissions-system-devices-symbolic",
|
||||
_ ("System Device Access"),
|
||||
_ ("Can access system devices which require elevated permissions"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SCREEN) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"permissions-screen-contents-symbolic",
|
||||
_ ("Screen Contents Access"),
|
||||
_ ("Can access the contents of the screen or other windows"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_X11) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"permissions-legacy-windowing-system-symbolic",
|
||||
_ ("Legacy Windowing System"),
|
||||
_ ("Always uses a legacy windowing system (X11)"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"earth-symbolic",
|
||||
_ ("Arbitrary Permissions"),
|
||||
_ ("Can acquire arbitrary permissions"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SETTINGS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("User Settings"),
|
||||
_ ("Can access and change user settings"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL) != 0,
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"drive-harddisk-symbolic",
|
||||
_ ("Full File System Read/Write Access"),
|
||||
_ ("Can read and write all data on the file system"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) != 0 &&
|
||||
!(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"user-home-symbolic",
|
||||
_ ("Home Folder Read/Write Access"),
|
||||
_ ("Can read and write all data in your home directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ) != 0 &&
|
||||
!(perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"folder-symbolic",
|
||||
_ ("Full File System Read Access"),
|
||||
_ ("Can read all data on the file system"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_READ) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ))),
|
||||
BZ_IMPORTANCE_IMPORTANT,
|
||||
"user-home-symbolic",
|
||||
_ ("Home Folder Read Access"),
|
||||
_ ("Can read all data in your home directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL))),
|
||||
fs_importance,
|
||||
"folder-download-symbolic",
|
||||
_ ("Download Folder Read/Write Access"),
|
||||
_ ("Can read and write all data in your downloads directory"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
((perm_flags & BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ) != 0 &&
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ))),
|
||||
fs_importance,
|
||||
"folder-download-symbolic",
|
||||
_ ("Download Folder Read Access"),
|
||||
_ ("Can read all data in your downloads directory"),
|
||||
NULL, NULL, NULL);
|
||||
if (perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)
|
||||
continue;
|
||||
|
||||
for (i = 0; filesystem_full != NULL && i < filesystem_full->len; i++)
|
||||
if ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) &&
|
||||
path->type == BZ_FILESYSTEM_PATH_HOME_SUBDIR)
|
||||
continue;
|
||||
|
||||
add_row_if_permission (store, TRUE, fs_importance, fs_icon, fs_title,
|
||||
_ ("Can read and write all data in the directory"),
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
for (i = 0; filesystem_read != NULL && i < filesystem_read->len; i++)
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (filesystem_read, i);
|
||||
g_autofree char *fs_title = bz_filesystem_path_to_display_string (path);
|
||||
const char *fs_icon = bz_filesystem_path_to_icon_name (path);
|
||||
|
||||
if (perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)
|
||||
continue;
|
||||
|
||||
if ((perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ)) &&
|
||||
path->type == BZ_FILESYSTEM_PATH_HOME_SUBDIR)
|
||||
continue;
|
||||
|
||||
add_row_if_permission (store, TRUE, fs_importance, fs_icon, fs_title,
|
||||
_ ("Can read all data in the directory"),
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
if (include_no_access_rows)
|
||||
add_row_if_permission (store,
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ)) &&
|
||||
filesystem_read == NULL && filesystem_full == NULL,
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"folder-symbolic",
|
||||
_ ("No File System Access"),
|
||||
_ ("Cannot access the file system at all"),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("Uses System Services"),
|
||||
_ ("Can request data from non-portal system services"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("Uses Session Services"),
|
||||
_ ("Can request data from non-portal session services"),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
for (i = 0; i < n_bus_policies; i++)
|
||||
{
|
||||
const BzBusPolicy *policy = bus_policies[i];
|
||||
const char *well_known_title = NULL;
|
||||
const char *well_known_desc = NULL;
|
||||
g_autofree char *bus_title = NULL;
|
||||
const char *bus_description = NULL;
|
||||
gboolean is_system_tray = FALSE;
|
||||
|
||||
is_system_tray = g_str_equal (policy->bus_name, "org.kde.StatusNotifierWatcher") ||
|
||||
g_str_equal (policy->bus_name, "com.canonical.indicator.application");
|
||||
|
||||
if (is_system_tray && has_system_tray) // if not filtered, then there would be 2 entries for tray icon
|
||||
continue;
|
||||
|
||||
if (is_system_tray)
|
||||
has_system_tray = TRUE;
|
||||
|
||||
if (lookup_well_known_bus_policy (policy->bus_name, &well_known_title, &well_known_desc))
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (filesystem_full, i);
|
||||
g_autofree char *fs_title = bz_filesystem_path_to_display_string (path);
|
||||
const char *fs_icon = bz_filesystem_path_to_icon_name (path);
|
||||
|
||||
if (perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)
|
||||
continue;
|
||||
|
||||
if ((perm_flags & BZ_APP_PERMISSIONS_FLAGS_HOME_FULL) &&
|
||||
path->type == BZ_FILESYSTEM_PATH_HOME_SUBDIR)
|
||||
continue;
|
||||
|
||||
add_row_if_permission (store,
|
||||
TRUE,
|
||||
fs_importance,
|
||||
fs_icon,
|
||||
fs_title,
|
||||
_ ("Can read and write all data in the directory"),
|
||||
NULL, NULL, NULL);
|
||||
bus_title = g_strdup (well_known_title);
|
||||
bus_description = well_known_desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
bus_title = format_bus_policy_title (policy);
|
||||
bus_description = format_bus_policy_subtitle (policy);
|
||||
}
|
||||
|
||||
for (i = 0; filesystem_read != NULL && i < filesystem_read->len; i++)
|
||||
{
|
||||
const BzFilesystemPath *path = g_ptr_array_index (filesystem_read, i);
|
||||
g_autofree char *fs_title = bz_filesystem_path_to_display_string (path);
|
||||
const char *fs_icon = bz_filesystem_path_to_icon_name (path);
|
||||
|
||||
if (perm_flags & BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL)
|
||||
continue;
|
||||
|
||||
if ((perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ)) &&
|
||||
path->type == BZ_FILESYSTEM_PATH_HOME_SUBDIR)
|
||||
continue;
|
||||
|
||||
add_row_if_permission (store,
|
||||
TRUE,
|
||||
fs_importance,
|
||||
fs_icon,
|
||||
fs_title,
|
||||
_ ("Can read all data in the directory"),
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
add_row_if_permission (store,
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_FILESYSTEM_OTHER |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_HOME_READ |
|
||||
BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_FULL |
|
||||
BZ_APP_PERMISSIONS_FLAGS_DOWNLOADS_READ)) &&
|
||||
filesystem_read == NULL && filesystem_full == NULL,
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"folder-symbolic",
|
||||
_ ("No File System Access"),
|
||||
_ ("Cannot access the file system at all"),
|
||||
add_row_if_permission (store, TRUE, BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic", bus_title, bus_description,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("Uses System Services"),
|
||||
_ ("Can request data from non-portal system services"),
|
||||
NULL, NULL, NULL);
|
||||
add_row_if_permission (store,
|
||||
(perm_flags & BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS) != 0,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
_ ("Uses Session Services"),
|
||||
_ ("Can request data from non-portal session services"),
|
||||
NULL, NULL, NULL);
|
||||
if (include_no_access_rows)
|
||||
add_row_if_permission (store,
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS |
|
||||
BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS |
|
||||
BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER)) &&
|
||||
n_bus_policies == 0,
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"emblem-system-symbolic",
|
||||
_ ("No Service Access"),
|
||||
_ ("Cannot access non-portal session or system services at all"),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
for (i = 0; i < n_bus_policies; i++)
|
||||
{
|
||||
const BzBusPolicy *policy = bus_policies[i];
|
||||
const char *well_known_title = NULL;
|
||||
const char *well_known_desc = NULL;
|
||||
g_autofree char *bus_title = NULL;
|
||||
const char *bus_description = NULL;
|
||||
gboolean is_system_tray = FALSE;
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
is_system_tray = g_str_equal (policy->bus_name, "org.kde.StatusNotifierWatcher") ||
|
||||
g_str_equal (policy->bus_name, "com.canonical.indicator.application");
|
||||
GListModel *
|
||||
bz_safety_calculator_analyze_entry (BzEntry *entry)
|
||||
{
|
||||
g_autoptr (BzAppPermissions) permissions = NULL;
|
||||
g_autoptr (GListModel) permissions_model = NULL;
|
||||
GListStore *store = NULL;
|
||||
gboolean is_verified = FALSE;
|
||||
gboolean is_foss = FALSE;
|
||||
guint n_items = 0;
|
||||
guint i = 0;
|
||||
|
||||
if (is_system_tray && has_system_tray) // if not filtered, then there would be 2 entries for tray icon
|
||||
continue;
|
||||
g_return_val_if_fail (BZ_IS_ENTRY (entry), NULL);
|
||||
|
||||
if (is_system_tray)
|
||||
has_system_tray = TRUE;
|
||||
is_verified = bz_entry_is_verified (entry);
|
||||
is_foss = bz_entry_get_is_foss (entry);
|
||||
|
||||
if (lookup_well_known_bus_policy (policy->bus_name, &well_known_title, &well_known_desc))
|
||||
{
|
||||
bus_title = g_strdup (well_known_title);
|
||||
bus_description = well_known_desc;
|
||||
}
|
||||
else
|
||||
{
|
||||
bus_title = format_bus_policy_title (policy);
|
||||
bus_description = format_bus_policy_subtitle (policy);
|
||||
}
|
||||
g_object_get (entry, "permissions", &permissions, NULL);
|
||||
permissions_model = bz_safety_calculator_analyze_permissions (permissions, TRUE);
|
||||
|
||||
add_row_if_permission (store,
|
||||
TRUE,
|
||||
BZ_IMPORTANCE_WARNING,
|
||||
"emblem-system-symbolic",
|
||||
bus_title,
|
||||
bus_description,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
store = g_list_store_new (BZ_TYPE_SAFETY_ROW);
|
||||
n_items = g_list_model_get_n_items (permissions_model);
|
||||
for (i = 0; i < n_items; i++)
|
||||
{
|
||||
g_autoptr (GObject) row = NULL;
|
||||
|
||||
add_row_if_permission (store,
|
||||
!(perm_flags & (BZ_APP_PERMISSIONS_FLAGS_SYSTEM_BUS |
|
||||
BZ_APP_PERMISSIONS_FLAGS_SESSION_BUS |
|
||||
BZ_APP_PERMISSIONS_FLAGS_BUS_POLICY_OTHER)) &&
|
||||
n_bus_policies == 0,
|
||||
BZ_IMPORTANCE_UNIMPORTANT,
|
||||
"emblem-system-symbolic",
|
||||
_ ("No Service Access"),
|
||||
_ ("Cannot access non-portal session or system services at all"),
|
||||
NULL, NULL, NULL);
|
||||
row = g_list_model_get_item (permissions_model, i);
|
||||
g_list_store_append (store, row);
|
||||
}
|
||||
|
||||
add_row_if_permission (store,
|
||||
|
|
@ -376,8 +394,6 @@ bz_safety_calculator_analyze_entry (BzEntry *entry)
|
|||
_ ("The source code is public and can be independently audited, which makes the app more likely to be safe"));
|
||||
}
|
||||
|
||||
g_clear_object (&permissions);
|
||||
|
||||
return G_LIST_MODEL (store);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "bz-app-permissions.h"
|
||||
#include "bz-context-row.h"
|
||||
#include "bz-entry.h"
|
||||
#include "bz-safety-row.h"
|
||||
|
|
@ -36,6 +37,10 @@ typedef enum
|
|||
|
||||
#define BZ_TYPE_HIGH_RISK_GROUP (bz_high_risk_group_get_type ())
|
||||
|
||||
GListModel *
|
||||
bz_safety_calculator_analyze_permissions (BzAppPermissions *permissions,
|
||||
gboolean include_no_access_rows);
|
||||
|
||||
GListModel *
|
||||
bz_safety_calculator_analyze_entry (BzEntry *entry);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue