From 5f820ddfa2975f0fd9457df434a7cd43fb740cdd Mon Sep 17 00:00:00 2001
From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com>
Date: Sun, 17 May 2026 16:49:10 +0200
Subject: [PATCH 1/2] Add "arbitrary permissions" page
---
src/bz-safety-dialog.blp | 196 +++++++++++++++++++++++++++------------
src/bz-safety-dialog.c | 170 ++++++++++++++++++++++++++++-----
2 files changed, 281 insertions(+), 85 deletions(-)
diff --git a/src/bz-safety-dialog.blp b/src/bz-safety-dialog.blp
index 22acf396..04921395 100644
--- a/src/bz-safety-dialog.blp
+++ b/src/bz-safety-dialog.blp
@@ -8,98 +8,172 @@ template $BzSafetyDialog: Adw.Bin {
show-title: false;
}
- content: ScrolledWindow {
- hscrollbar-policy: never;
-
- Adw.Clamp {
- maximum-size: 640;
- tightening-threshold: 400;
-
- Box {
+ content: Adw.Carousel carousel {
+ interactive: false;
+ allow-scroll-wheel: false;
+ allow-mouse-drag: false;
+ allow-long-swipes: false;
+ hexpand: true;
+
+ ScrolledWindow {
+ hscrollbar-policy: never;
+ hexpand: true;
+
+ Box global_box {
orientation: vertical;
- spacing: 24;
- margin-start: 24;
- margin-end: 24;
- margin-top: 24;
- margin-bottom: 24;
+ spacing: 12;
+ margin-start: 18;
+ margin-end: 18;
+ margin-top: 18;
+ margin-bottom: 18;
- $BzLozenge lozenge {
- title: _("Safe");
+ $BzLozenge {
+ title: _("Arbitrary Permissions");
icon-names: [
- "app-safety-ok-symbolic",
+ "earth-symbolic",
];
- importance: unimportant;
+ importance: important;
+ margin-bottom: 12;
}
- ListBox permissions_list {
+ ListBox {
+ styles [
+ "boxed-list",
+ ]
+
+ ListBoxRow {
+ activatable: false;
+ selectable: false;
+
+ child: Label {
+ wrap: true;
+ xalign: 0;
+ use-markup: true;
+ margin-top: 12;
+ margin-bottom: 12;
+ margin-start: 12;
+ margin-end: 12;
+ label: _("This app has a permission that indirectly allows it to grant itself any other permission it wants, bypassing the Flatpak sandbox.\n\nIt can therefore do anything a normal, non-sandboxed application can do. Like acessing all your files, and connecting the internet.\n\nViewing the other permissions may still give a better idea of what the app is likely to do.");
+ };
+ }
+ }
+
+ ListBox {
selection-mode: none;
styles [
"boxed-list",
]
+
+ Adw.ButtonRow {
+ title: _("View Other Permissions");
+ end-icon-name: "go-next-symbolic";
+ activated => $next_page(template);
+ }
}
+ }
+ }
- Adw.PreferencesGroup {
- margin-top: 10;
- title: _("Details");
+ ScrolledWindow {
+ hscrollbar-policy: never;
+ hexpand: true;
- Adw.ActionRow {
- title: _("License");
- subtitle: bind template.entry as <$BzEntry>.project-license;
- subtitle-selectable: true;
+ Adw.Clamp {
+ maximum-size: 640;
+ tightening-threshold: 400;
- styles [
- "property",
- ]
+ Box {
+ orientation: vertical;
+ spacing: 24;
+ margin-start: 24;
+ margin-end: 24;
+ margin-top: 24;
+ margin-bottom: 24;
+
+ $BzLozenge lozenge {
+ title: _("Safe");
+
+ icon-names: [
+ "app-safety-ok-symbolic",
+ ];
+
+ importance: unimportant;
}
- Adw.ActionRow {
- title: _("App ID");
- subtitle: bind template.entry as <$BzEntry>.id;
- subtitle-selectable: true;
+ ListBox permissions_list {
+ selection-mode: none;
styles [
- "property",
+ "boxed-list",
]
}
- Adw.ActionRow {
- title: _("SDK");
- subtitle: bind template.entry as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.title;
- subtitle-selectable: true;
- has-tooltip: true;
- tooltip-text: bind template.entry as <$BzFlatpakEntry>.application-runtime;
- visible: bind $invert_boolean($is_null(template.entry as <$BzFlatpakEntry>.runtime as <$BzResult>.object) as ) as ;
+ Adw.PreferencesGroup {
+ margin-top: 10;
+ title: _("Details");
- styles [
- "property",
- ]
+ Adw.ActionRow {
+ title: _("License");
+ subtitle: bind template.entry as <$BzEntry>.project-license;
+ subtitle-selectable: true;
+
+ styles [
+ "property",
+ ]
+ }
+
+ Adw.ActionRow {
+ title: _("App ID");
+ subtitle: bind template.entry as <$BzEntry>.id;
+ subtitle-selectable: true;
+
+ styles [
+ "property",
+ ]
+ }
- [suffix]
- MenuButton {
- visible: bind $invert_boolean($is_null(template.entry as <$BzEntry>.eol) as ) as ;
+ Adw.ActionRow {
+ title: _("SDK");
+ subtitle: bind template.entry as <$BzFlatpakEntry>.runtime as <$BzResult>.object as <$BzEntry>.title;
+ subtitle-selectable: true;
+ has-tooltip: true;
+ tooltip-text: bind template.entry as <$BzFlatpakEntry>.application-runtime;
+ visible: bind $invert_boolean(
+ $is_null(template.entry as <$BzFlatpakEntry>.runtime as <$BzResult>.object) as
+ ) as ;
styles [
- "error",
- "flat",
+ "property",
]
- valign: center;
- icon-name: "dialog-warning-symbolic";
-
- popover: Popover {
- child: Label {
- margin-top: 8;
- margin-bottom: 8;
- margin-start: 8;
- margin-end: 8;
- max-width-chars: 35;
- wrap: true;
- label: _("This app uses an outdated version of the software platform (SDK) and might contain bugs or security vulnerabilities which will not be fixed.");
+ [suffix]
+ MenuButton {
+ visible: bind $invert_boolean($is_null(template.entry as <$BzEntry>.eol) as ) as ;
+
+ styles [
+ "error",
+ "flat",
+ ]
+
+ valign: center;
+ icon-name: "dialog-warning-symbolic";
+
+ popover: Popover {
+ child: Label {
+ margin-top: 8;
+ margin-bottom: 8;
+ margin-start: 8;
+ margin-end: 8;
+ max-width-chars: 35;
+ wrap: true;
+ label: _(
+ "This app uses an outdated version of the software platform (SDK) and might contain bugs or security vulnerabilities which will not be fixed."
+ );
+ };
};
- };
+ }
}
}
}
diff --git a/src/bz-safety-dialog.c b/src/bz-safety-dialog.c
index 602d2a20..d11dbb83 100644
--- a/src/bz-safety-dialog.c
+++ b/src/bz-safety-dialog.c
@@ -22,6 +22,7 @@
#include
+#include "bz-app-permissions.h"
#include "bz-context-row.h"
#include "bz-entry.h"
#include "bz-lozenge.h"
@@ -30,14 +31,23 @@
#include "bz-safety-row.h"
#include "bz-template-callbacks.h"
+#define ANIMATION_DURATION 300
+
struct _BzSafetyDialog
{
AdwBin parent_instance;
BzEntry *entry;
- BzLozenge *lozenge;
- GtkListBox *permissions_list;
+ gboolean has_sandbox_escape;
+
+ AdwAnimation *width_animation;
+ AdwAnimation *height_animation;
+
+ BzLozenge *lozenge;
+ GtkListBox *permissions_list;
+ AdwCarousel *carousel;
+ GtkBox *global_box;
};
G_DEFINE_FINAL_TYPE (BzSafetyDialog, bz_safety_dialog, ADW_TYPE_BIN)
@@ -51,8 +61,8 @@ enum
static GParamSpec *props[LAST_PROP] = { 0 };
-static AdwActionRow *create_permission_row (BzSafetyRow *row_data);
-static void update_permissions_list (BzSafetyDialog *self);
+static void update_permissions_list (BzSafetyDialog *self);
+static void animate_to_page (BzSafetyDialog *self, guint page_index);
static void
bz_safety_dialog_dispose (GObject *object)
@@ -60,6 +70,8 @@ bz_safety_dialog_dispose (GObject *object)
BzSafetyDialog *self = BZ_SAFETY_DIALOG (object);
g_clear_object (&self->entry);
+ g_clear_object (&self->width_animation);
+ g_clear_object (&self->height_animation);
G_OBJECT_CLASS (bz_safety_dialog_parent_class)->dispose (object);
}
@@ -104,6 +116,91 @@ bz_safety_dialog_set_property (GObject *object,
}
}
+static void
+get_target_size (BzSafetyDialog *self,
+ guint page_index,
+ int *out_width,
+ int *out_height)
+{
+ if (page_index == 0)
+ {
+ int nat = 0;
+ *out_width = 400;
+ gtk_widget_measure (GTK_WIDGET (self->global_box),
+ GTK_ORIENTATION_VERTICAL,
+ *out_width,
+ NULL, &nat, NULL, NULL);
+ *out_height = CLAMP (nat + 48, 100, 600);
+ }
+ else
+ {
+ *out_width = 640;
+ *out_height = 576;
+ }
+}
+
+static void
+animate_to_page (BzSafetyDialog *self,
+ guint page_index)
+{
+ AdwDialog *dialog = NULL;
+ int target_width = 0;
+ int target_height = 0;
+ int cur_w = 0;
+ int cur_h = 0;
+
+ dialog = ADW_DIALOG (gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_DIALOG));
+ if (dialog == NULL)
+ return;
+
+ if (self->width_animation == NULL || self->height_animation == NULL)
+ return;
+
+ get_target_size (self, page_index, &target_width, &target_height);
+
+ cur_w = adw_dialog_get_content_width (dialog);
+ cur_h = adw_dialog_get_content_height (dialog);
+
+ adw_animation_skip (self->width_animation);
+ adw_animation_skip (self->height_animation);
+
+ adw_timed_animation_set_duration (ADW_TIMED_ANIMATION (self->width_animation), ANIMATION_DURATION);
+ adw_timed_animation_set_duration (ADW_TIMED_ANIMATION (self->height_animation), ANIMATION_DURATION);
+ adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->width_animation), cur_w);
+ adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->width_animation), target_width);
+ adw_timed_animation_set_value_from (ADW_TIMED_ANIMATION (self->height_animation), cur_h);
+ adw_timed_animation_set_value_to (ADW_TIMED_ANIMATION (self->height_animation), target_height);
+ adw_animation_play (self->width_animation);
+ adw_animation_play (self->height_animation);
+}
+
+static void
+on_dialog_map (BzSafetyDialog *self)
+{
+ AdwDialog *dialog = NULL;
+ int target_width = 0;
+ int target_height = 0;
+
+ dialog = ADW_DIALOG (gtk_widget_get_ancestor (GTK_WIDGET (self), ADW_TYPE_DIALOG));
+ if (dialog == NULL)
+ return;
+
+ get_target_size (self, self->has_sandbox_escape ? 0 : 1, &target_width, &target_height);
+ adw_dialog_set_content_width (dialog, target_width);
+ adw_dialog_set_content_height (dialog, target_height);
+}
+
+static void
+next_page (BzSafetyDialog *self,
+ GtkButton *button)
+{
+ GtkWidget *page = NULL;
+
+ page = gtk_widget_get_last_child (GTK_WIDGET (self->carousel));
+ adw_carousel_scroll_to (self->carousel, page, TRUE);
+ animate_to_page (self, 1);
+}
+
static void
bz_safety_dialog_class_init (BzSafetyDialogClass *klass)
{
@@ -133,6 +230,9 @@ bz_safety_dialog_class_init (BzSafetyDialogClass *klass)
gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, lozenge);
gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, permissions_list);
+ gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, carousel);
+ gtk_widget_class_bind_template_child (widget_class, BzSafetyDialog, global_box);
+ gtk_widget_class_bind_template_callback (widget_class, next_page);
}
static void
@@ -144,16 +244,27 @@ bz_safety_dialog_init (BzSafetyDialog *self)
AdwDialog *
bz_safety_dialog_new (BzEntry *entry)
{
- BzSafetyDialog *widget = NULL;
- AdwDialog *dialog = NULL;
+ BzSafetyDialog *widget = NULL;
+ AdwDialog *dialog = NULL;
+ AdwAnimationTarget *width_target = NULL;
+ AdwAnimationTarget *height_target = NULL;
- widget = g_object_new (BZ_TYPE_SAFETY_DIALOG, "entry", entry, NULL);
+ widget = g_object_new (BZ_TYPE_SAFETY_DIALOG, NULL);
dialog = adw_dialog_new ();
adw_dialog_set_content_height (dialog, 576);
adw_dialog_set_content_width (dialog, 640);
adw_dialog_set_child (dialog, GTK_WIDGET (widget));
+ width_target = adw_property_animation_target_new (G_OBJECT (dialog), "content-width");
+ widget->width_animation = adw_timed_animation_new (GTK_WIDGET (widget), 0, 0, ANIMATION_DURATION, width_target);
+ height_target = adw_property_animation_target_new (G_OBJECT (dialog), "content-height");
+ widget->height_animation = adw_timed_animation_new (GTK_WIDGET (widget), 0, 0, ANIMATION_DURATION, height_target);
+
+ g_object_set (widget, "entry", entry, NULL);
+
+ g_signal_connect_swapped (widget, "map", G_CALLBACK (on_dialog_map), widget);
+
return dialog;
}
@@ -170,25 +281,18 @@ bz_safety_dialog_page_new (BzEntry *entry)
return page;
}
-static AdwActionRow *
-create_permission_row (BzSafetyRow *row_data)
-{
- return bz_context_row_new (bz_safety_row_get_icon_name (row_data),
- bz_safety_row_get_importance (row_data),
- bz_safety_row_get_title (row_data),
- bz_safety_row_get_subtitle (row_data));
-}
-
static void
update_permissions_list (BzSafetyDialog *self)
{
const char *icon_names[2];
- const char *app_name = NULL;
- g_autofree char *title_text = NULL;
- BzImportance importance = BZ_IMPORTANCE_UNIMPORTANT;
- GtkWidget *child = NULL;
- g_autoptr (GListModel) model = NULL;
- guint n_items = 0;
+ const char *app_name = NULL;
+ g_autofree char *title_text = NULL;
+ BzImportance importance = BZ_IMPORTANCE_UNIMPORTANT;
+ GtkWidget *child = NULL;
+ g_autoptr (GListModel) model = NULL;
+ guint n_items = 0;
+ BzAppPermissions *permissions = NULL;
+ BzAppPermissionsFlags perm_flags = BZ_APP_PERMISSIONS_FLAGS_NONE;
while ((child = gtk_widget_get_first_child (GTK_WIDGET (self->permissions_list))) != NULL)
gtk_list_box_remove (self->permissions_list, child);
@@ -196,11 +300,26 @@ update_permissions_list (BzSafetyDialog *self)
if (self->entry == NULL)
return;
- app_name = bz_entry_get_title (self->entry);
+ g_object_get (self->entry, "permissions", &permissions, NULL);
+ if (permissions != NULL)
+ {
+ perm_flags = bz_app_permissions_get_flags (permissions);
+ g_object_unref (permissions);
+ }
+
+ self->has_sandbox_escape = (perm_flags & BZ_APP_PERMISSIONS_FLAGS_ESCAPE_SANDBOX) != 0;
+
+ if (!self->has_sandbox_escape)
+ {
+ GtkWidget *page = gtk_widget_get_last_child (GTK_WIDGET (self->carousel));
+ adw_carousel_scroll_to (self->carousel, page, FALSE);
+ }
+ app_name = bz_entry_get_title (self->entry);
model = bz_safety_calculator_analyze_entry (self->entry);
importance = bz_safety_calculator_calculate_rating (self->entry);
n_items = g_list_model_get_n_items (model);
+
for (gint level = BZ_IMPORTANCE_IMPORTANT; level >= BZ_IMPORTANCE_UNIMPORTANT; level--)
{
for (gint j = 0; j < n_items; j++)
@@ -213,7 +332,10 @@ update_permissions_list (BzSafetyDialog *self)
row_importance = bz_safety_row_get_importance (row_data);
if (row_importance != level)
continue;
- row = create_permission_row (row_data);
+ row = bz_context_row_new (bz_safety_row_get_icon_name (row_data),
+ bz_safety_row_get_importance (row_data),
+ bz_safety_row_get_title (row_data),
+ bz_safety_row_get_subtitle (row_data));
gtk_list_box_append (self->permissions_list, GTK_WIDGET (row));
}
}
From 476d22f38c546922fe3995d964fc823092d98544 Mon Sep 17 00:00:00 2001
From: Alexander Vanhee <160625516+AlexanderVanhee@users.noreply.github.com>
Date: Sun, 17 May 2026 18:00:34 +0200
Subject: [PATCH 2/2] Make bit wider
---
src/bz-safety-dialog.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/bz-safety-dialog.c b/src/bz-safety-dialog.c
index d11dbb83..18a04eef 100644
--- a/src/bz-safety-dialog.c
+++ b/src/bz-safety-dialog.c
@@ -125,7 +125,7 @@ get_target_size (BzSafetyDialog *self,
if (page_index == 0)
{
int nat = 0;
- *out_width = 400;
+ *out_width = 450;
gtk_widget_measure (GTK_WIDGET (self->global_box),
GTK_ORIENTATION_VERTICAL,
*out_width,