APP PERMISSIONS TOGGLES ARE DONE

This commit is contained in:
GloriousEggroll 2025-04-03 18:38:45 -06:00
parent c5cbaf45d4
commit cf594464a5
3 changed files with 614 additions and 73 deletions

View file

@ -1197,7 +1197,7 @@ def get_perm_key_file(app_id: str | None, override=False, system=False) -> GLib
return key_file
def add_file_permissions(app_id: str, path: str, system=False) -> tuple[bool, str]:
def add_file_permissions(app_id: str, path: str, perm_type=None, system=False) -> tuple[bool, str]:
"""
Add filesystem permissions to a Flatpak application.
@ -1214,7 +1214,7 @@ def add_file_permissions(app_id: str, path: str, system=False) -> tuple[bool, st
try:
key_file = get_perm_key_file(app_id, system)
perm_type = perm_type or "filesystem"
# Handle special case for home directory
if path.lower() == "host":
filesystem_path = "host"
@ -1229,32 +1229,35 @@ def add_file_permissions(app_id: str, path: str, system=False) -> tuple[bool, st
filesystem_path = path.rstrip('/')
if not key_file.has_group("Context"):
key_file.set_string("Context", "filesystems", "")
key_file.set_string("Context", perm_type, "")
# Now get the keys
context_keys = key_file.get_keys("Context")
# Check if perm_type exists in the section
if "filesystems" not in str(context_keys):
if perm_type not in str(context_keys):
# Create the key with an empty string
key_file.set_string("Context", "filesystems", "")
key_file.set_string("Context", perm_type, "")
# Get existing filesystem paths
existing_paths = key_file.get_string("Context", "filesystems")
if existing_paths is None:
existing_paths = key_file.get_string("Context", perm_type)
if existing_paths is None or existing_paths == "":
# If no filesystems entry exists, create it
key_file.set_string("Context", "filesystems", filesystem_path)
key_file.set_string("Context", perm_type, filesystem_path)
else:
# Split existing paths and check if our path already exists
print(existing_paths)
existing_paths_list = existing_paths.split(';')
print(existing_paths_list)
# Normalize paths for comparison (remove trailing slashes, convert to absolute paths)
normalized_new_path = os.path.abspath(filesystem_path.rstrip('/'))
normalized_existing_paths = [os.path.abspath(p.rstrip('/')) for p in existing_paths_list]
print(normalized_new_path)
print(normalized_existing_paths)
# Only add if the path doesn't already exist
if normalized_new_path not in normalized_existing_paths:
key_file.set_string("Context", "filesystems",
key_file.set_string("Context", perm_type,
existing_paths + filesystem_path + ";")
# Write the modified metadata back
@ -1269,7 +1272,7 @@ def add_file_permissions(app_id: str, path: str, system=False) -> tuple[bool, st
return False, f"Failed to modify permissions: {str(e)}"
def remove_file_permissions(app_id: str, path: str, system=False) -> tuple[bool, str]:
def remove_file_permissions(app_id: str, path: str, perm_type=None, system=False) -> tuple[bool, str]:
"""
Remove filesystem permissions from a Flatpak application.
@ -1285,6 +1288,7 @@ def remove_file_permissions(app_id: str, path: str, system=False) -> tuple[bool,
"""
try:
key_file = get_perm_key_file(app_id, system)
perm_type = perm_type or "filesystem"
# Handle special case for home directory
if path.lower() == "host":
@ -1300,7 +1304,7 @@ def remove_file_permissions(app_id: str, path: str, system=False) -> tuple[bool,
filesystem_path = path.rstrip('/')
# Get existing filesystem paths
existing_paths = key_file.get_string("Context", "filesystems")
existing_paths = key_file.get_string("Context", perm_type)
if existing_paths is None:
return True, f"No filesystem permissions to remove for {app_id}"
@ -1322,9 +1326,9 @@ def remove_file_permissions(app_id: str, path: str, system=False) -> tuple[bool,
new_permissions = ";".join(filtered_paths_list)
if new_permissions:
# Save changes
key_file.set_string("Context", "filesystems", new_permissions)
key_file.set_string("Context", perm_type, new_permissions)
else:
key_file.remove_key("Context", "filesystems")
key_file.remove_key("Context", perm_type)
# Write the modified metadata back
try:
@ -1577,6 +1581,9 @@ def add_permission_value(app_id: str, perm_type: str, value: str, system=False)
key, val = parts
if val not in ['talk', 'own']:
return False, "Value must be in format 'key=value' with value as 'talk' or 'own'"
# Set the value
key_file.set_string(perm_type, key, val)
@ -2141,10 +2148,7 @@ def portal_get_app_permissions(app_id: str):
# Format and return the results
if app_permissions:
success_message = f"\nFound permissions for {app_id}:\n"
for portal, permission in app_permissions.items():
success_message += f"- {portal}: {permission}\n"
return True, success_message.strip()
return True, app_permissions
return False, f"No permissions found for {app_id} in any portal"
@ -2239,11 +2243,11 @@ def main():
parser.add_argument('--list-file-perms', action='store_true',
help='List configured file permissions for an app')
parser.add_argument('--list-other-perm-toggles', type=str, metavar='PERM_NAME',
help='List configured other permission toggles for an app (e.g. "shared", "sockets", "devices", "features", "persistent")')
help='List configured other permission toggles for an app (e.g. "shared", "sockets", "devices", "features")')
parser.add_argument('--toggle-other-perms', type=str, metavar=('ENABLE/DISABLE'),
help='Toggle other permissions on/off (True/False)')
parser.add_argument('--perm-type', type=str,
help='Type of permission to toggle (shared, sockets, devices, features)')
help='Type of permission to toggle (shared, sockets, devices, features, persistent)')
parser.add_argument('--perm-option', type=str,
help='Specific permission option to toggle (e.g. network, ipc)')
parser.add_argument('--list-other-perm-values', type=str, metavar='PERM_NAME',
@ -2262,7 +2266,7 @@ def main():
parser.add_argument('--global-list-file-perms', action='store_true',
help='List configured file permissions for an app')
parser.add_argument('--global-list-other-perm-toggles', type=str, metavar='PERM_NAME',
help='List configured other permission toggles for an app (e.g. "shared", "sockets", "devices", "features", "persistent")')
help='List configured other permission toggles for an app (e.g. "shared", "sockets", "devices", "features")')
parser.add_argument('--global-toggle-other-perms', type=str, metavar=('ENABLE/DISABLE'),
help='Toggle other permissions on/off (True/False)')
parser.add_argument('--global-list-other-perm-values', type=str, metavar='PERM_NAME',
@ -2538,14 +2542,14 @@ def handle_subcategories(args, searcher):
def handle_add_file_perms(args, searcher):
try:
success, message = add_file_permissions(args.id, args.add_file_perms, args.system)
success, message = add_file_permissions(args.id, args.add_file_perms, args.perm_type, args.system)
print(f"{message}")
except GLib.Error as e:
print(f"{str(e)}")
def handle_remove_file_perms(args, searcher):
try:
success, message = remove_file_permissions(args.id, args.remove_file_perms, args.system)
success, message = remove_file_permissions(args.id, args.remove_file_perms, args.perm_type, args.system)
print(f"{message}")
except GLib.Error as e:
print(f"{str(e)}")

539
main.py
View file

@ -313,6 +313,7 @@ class MainWindow(Gtk.Window):
self.create_panels()
self.refresh_data()
#self.refresh_local()
# Select Trending by default
self.select_default_category()
@ -1372,7 +1373,7 @@ class MainWindow(Gtk.Window):
condition=lambda x: True
)
add_rm_icon = "list-remove"
add_rm_style = "dark-remove-buton"
add_rm_style = "dark-remove-button"
else:
button = self.create_button(
self.on_install_clicked,
@ -1389,6 +1390,23 @@ class MainWindow(Gtk.Window):
button.get_style_context().add_class(add_rm_style)
buttons_box.pack_end(button, False, False, 0)
# Install/Remove button
if is_installed:
button = self.create_button(
self.on_app_options_clicked,
app,
None,
condition=lambda x: True
)
add_options_icon = "system-run"
add_options_style = "dark-remove-button"
if button:
use_icon = Gio.Icon.new_for_string(add_options_icon)
button.set_image(Gtk.Image.new_from_gicon(use_icon, Gtk.IconSize.BUTTON))
button.get_style_context().add_class(add_options_style)
buttons_box.pack_end(button, False, False, 0)
# Add Update button if available
if is_updatable:
update_button = self.create_button(
@ -1649,6 +1667,525 @@ class MainWindow(Gtk.Window):
dialog.destroy()
def _add_bus_section(self, app_id, app, listbox, section_title, perm_type):
"""Helper method to add System Bus or Session Bus section"""
# Add separator
sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
listbox.add(sep)
# Add section header
row_header = Gtk.ListBoxRow(selectable=False)
box_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
label_header = Gtk.Label(label=f"<b>{section_title}</b>",
use_markup=True, xalign=0)
box_header.pack_start(label_header, True, True, 0)
row_header.add(box_header)
listbox.add(row_header)
# Get permissions
success, perms = libflatpak_query.list_other_perm_values(app_id, perm_type, self.system_mode)
if not success:
perms = {"paths": []}
# Add Talks section
talks_row = Gtk.ListBoxRow(selectable=False)
talks_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
talks_row.add(talks_box)
talks_header = Gtk.Label(label="Talks", xalign=0)
talks_box.pack_start(talks_header, False, False, 0)
# Add separator between header and paths
talks_box.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
False, False, 0)
# Add talk paths
for path in perms["paths"]:
if "talk" in path:
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=path.split("=")[0], xalign=0)
vbox.pack_start(label, True, True, 0)
btn = Gtk.Button(label="Remove")
btn.connect("clicked", self._on_remove_path, app_id, app, path, perm_type)
hbox.pack_end(btn, False, True, 0)
talks_box.add(row)
listbox.add(talks_row)
# Add Owns section
owns_row = Gtk.ListBoxRow(selectable=False)
owns_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
owns_row.add(owns_box)
owns_header = Gtk.Label(label="Owns", xalign=0)
owns_box.pack_start(owns_header, False, False, 0)
# Add separator between header and paths
owns_box.pack_start(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL),
False, False, 0)
# Add own paths
for path in perms["paths"]:
if "own" in path:
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=path.split("=")[0], xalign=0)
vbox.pack_start(label, True, True, 0)
btn = Gtk.Button(label="Remove")
btn.connect("clicked", self._on_remove_path, app_id, app, path, perm_type)
hbox.pack_end(btn, False, True, 0)
owns_box.add(row)
owns_row.show_all()
listbox.add(owns_row)
# Add add button
add_path_row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
add_path_row.add(hbox)
btn = Gtk.Button(label="Add Path")
btn.connect("clicked", self._on_add_path, app_id, app, perm_type)
hbox.pack_end(btn, False, True, 0)
listbox.add(add_path_row)
def _add_path_section(self, app_id, app, listbox, section_title, perm_type):
"""Helper method to add sections with paths (Persistent, Environment)"""
# Add separator
sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
listbox.add(sep)
# Add section header
row_header = Gtk.ListBoxRow(selectable=False)
box_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
label_header = Gtk.Label(label=f"<b>{section_title}</b>",
use_markup=True, xalign=0)
box_header.pack_start(label_header, True, True, 0)
row_header.add(box_header)
listbox.add(row_header)
# Get permissions
if perm_type == "persistent":
success, perms = libflatpak_query.list_other_perm_toggles(app_id, perm_type, self.system_mode)
else:
success, perms = libflatpak_query.list_other_perm_values(app_id, perm_type, self.system_mode)
if not success:
perms = {"paths": []}
# Add paths
for path in perms["paths"]:
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=path, xalign=0)
vbox.pack_start(label, True, True, 0)
btn = Gtk.Button(label="Remove")
btn.connect("clicked", self._on_remove_path, app_id, app, path, perm_type)
hbox.pack_end(btn, False, True, 0)
listbox.add(row)
# Add add button
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
btn = Gtk.Button(label="Add Path")
btn.connect("clicked", self._on_add_path, app_id, app, perm_type)
hbox.pack_end(btn, False, True, 0)
listbox.add(row)
def _add_filesystem_section(self, app_id, app, listbox, section_title):
"""Helper method to add the Filesystems section"""
# Add separator
sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
listbox.add(sep)
# Add section header
row_header = Gtk.ListBoxRow(selectable=False)
box_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
label_header = Gtk.Label(label=f"<b>{section_title}</b>",
use_markup=True, xalign=0)
box_header.pack_start(label_header, True, True, 0)
row_header.add(box_header)
listbox.add(row_header)
# Get filesystem permissions
success, perms = libflatpak_query.list_file_perms(app_id, self.system_mode)
if not success:
perms = {"paths": [], "special_paths": []}
# Add special paths as toggles
special_paths = [
("All user files", "home", "Access to all user files"),
("All system files", "host", "Access to all system files"),
("All system libraries, executables and static data", "host-os", "Access to system libraries and executables"),
("All system configurations", "host-etc", "Access to system configurations")
]
for display_text, option, description in special_paths:
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=display_text, xalign=0)
desc = Gtk.Label(label=description, xalign=0)
vbox.pack_start(label, True, True, 0)
vbox.pack_start(desc, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
switch.set_active(option in perms["special_paths"])
switch.set_sensitive(True)
switch.connect("state-set", self._on_switch_toggled, app_id, "filesystems", option)
hbox.pack_end(switch, False, True, 0)
listbox.add(row)
# Add normal paths with remove buttons
for path in perms["paths"]:
if path != "":
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=path, xalign=0)
vbox.pack_start(label, True, True, 0)
btn = Gtk.Button(label="Remove")
btn.connect("clicked", self._on_remove_path, app_id, app, path)
hbox.pack_end(btn, False, True, 0)
listbox.add(row)
# Add add button
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
btn = Gtk.Button(label="Add Path")
btn.connect("clicked", self._on_add_path, app_id, app)
hbox.pack_end(btn, False, True, 0)
listbox.add(row)
def on_app_options_clicked(self, button, app):
"""Handle the app options click"""
details = app.get_details()
app_id = details['id']
# Create window (as before)
self.options_window = Gtk.Window(title=f"{details['name']} Settings")
self.options_window.set_default_size(500, 700)
# Set subtitle
header_bar = Gtk.HeaderBar(title=f"{details['name']} Settings",
subtitle="List of resources selectively granted to the application")
header_bar.set_show_close_button(True)
self.options_window.set_titlebar(header_bar)
# Create main container with padding
box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
box_outer.set_border_width(20)
self.options_window.add(box_outer)
# Create scrolled window for content
scrolled = Gtk.ScrolledWindow()
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
# Create list box for options
listbox = Gtk.ListBox()
listbox.set_selection_mode(Gtk.SelectionMode.NONE)
# Add Portals section first
self._add_section(app_id, listbox, "Portals", section_options=[
("Background", "background", "Can run in the background"),
("Notifications", "notifications", "Can send notifications"),
("Microphone", "microphone", "Can listen to your microphone"),
("Speakers", "speakers", "Can play sounds to your speakers"),
("Camera", "camera", "Can record videos with your camera"),
("Location", "location", "Can access your location")
])
# Add other sections with correct permission types
self._add_section(app_id, listbox, "Shared", "shared", [
("Network", "network", "Can communicate over network"),
("Inter-process communications", "ipc", "Can communicate with other applications")
])
self._add_section(app_id, listbox, "Sockets", "sockets", [
("X11 windowing system", "x11", "Can access X11 display server"),
("Wayland windowing system", "wayland", "Can access Wayland display server"),
("Fallback to X11 windowing system", "fallback-x11", "Can fallback to X11 if Wayland unavailable"),
("PulseAudio sound server", "pulseaudio", "Can access PulseAudio sound system"),
("D-Bus session bus", "session-bus", "Can communicate with session D-Bus"),
("D-Bus system bus", "system-bus", "Can communicate with system D-Bus"),
("Secure Shell agent", "ssh-auth", "Can access SSH authentication agent"),
("Smart cards", "pcsc", "Can access smart card readers"),
("Printing system", "cups", "Can access printing subsystem"),
("GPG-Agent directories", "gpg-agent", "Can access GPG keyring"),
("Inherit Wayland socket", "inherit-wayland-socket", "Can inherit existing Wayland socket")
])
self._add_section(app_id, listbox, "Devices", "devices", [
("GPU Acceleration", "dri", "Can use hardware graphics acceleration"),
("Input devices", "input", "Can access input devices"),
("Virtualization", "kvm", "Can access virtualization services"),
("Shared memory", "shm", "Can use shared memory"),
("All devices (e.g. webcam)", "all", "Can access all device files")
])
self._add_section(app_id, listbox, "Features", "features", [
("Development syscalls", "devel", "Can perform development operations"),
("Programs from other architectures", "multiarch", "Can execute programs from other architectures"),
("Bluetooth", "bluetooth", "Can access Bluetooth hardware"),
("Controller Area Network bus", "canbus", "Can access CAN bus"),
("Application Shared Memory", "per-app-dev-shm", "Can use shared memory for IPC")
])
# Add Filesystems section
self._add_filesystem_section(app_id, app, listbox, "Filesystems")
self._add_path_section(app_id, app, listbox, "Persistent", "persistent")
self._add_path_section(app_id, app, listbox, "Environment", "environment")
self._add_bus_section(app_id, app, listbox, "System Bus", "system_bus")
self._add_bus_section(app_id, app, listbox, "Session Bus", "session_bus")
# Add widgets to container
box_outer.pack_start(scrolled, True, True, 0)
scrolled.add(listbox)
# Connect destroy signal
self.options_window.connect("destroy", lambda w: w.destroy())
# Show window
self.options_window.show_all()
def _add_section(self, app_id, listbox, section_title, perm_type=None, section_options=None):
"""Helper method to add a section with multiple options"""
# Add separator
sep = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)
listbox.add(sep)
# Add section header
row_header = Gtk.ListBoxRow(selectable=False)
box_header = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
label_header = Gtk.Label(label=f"<b>{section_title}</b>",
use_markup=True, xalign=0)
box_header.pack_start(label_header, True, True, 0)
row_header.add(box_header)
listbox.add(row_header)
# Handle portal permissions specially
if section_title == "Portals":
success, perms = libflatpak_query.portal_get_app_permissions(app_id)
if not success:
perms = {}
elif section_title in ["Persistent", "Environment", "System Bus", "Session Bus"]:
success, perms = libflatpak_query.list_other_perm_toggles(app_id, perm_type, self.system_mode)
if not success:
perms = {"paths": []}
else:
success, perms = libflatpak_query.list_other_perm_toggles(app_id, perm_type, self.system_mode)
if not success:
perms = {"paths": []}
if section_options:
# Add options
for display_text, option, description in section_options:
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=display_text, xalign=0)
desc = Gtk.Label(label=description, xalign=0)
vbox.pack_start(label, True, True, 0)
vbox.pack_start(desc, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
# Handle portal permissions differently
if section_title == "Portals":
if option in perms:
switch.set_active(perms[option] == 'yes')
switch.set_sensitive(True)
else:
switch.set_sensitive(False)
else:
switch.set_active(option in [p.lower() for p in perms["paths"]])
switch.set_sensitive(True)
switch.connect("state-set", self._on_switch_toggled, app_id, perm_type, option)
hbox.pack_end(switch, False, True, 0)
listbox.add(row)
def _on_switch_toggled(self, switch, state, app_id, perm_type, option):
"""Handle switch toggle events"""
if perm_type is None: # Portal section
success, message = libflatpak_query.portal_set_app_permissions(
option.lower(),
app_id,
"yes" if state else "no"
)
else:
success, message = libflatpak_query.toggle_other_perms(
app_id,
perm_type,
option.lower(),
state,
self.system_mode
)
if not success:
switch.set_active(not state)
print(f"Error: {message}")
def _on_remove_path(self, button, app_id, app, path, perm_type=None):
"""Handle remove path button click"""
if perm_type:
if perm_type == "persistent":
success, message = libflatpak_query.remove_file_permissions(
app_id,
path,
"persistent",
self.system_mode
)
else:
success, message = libflatpak_query.remove_permission_value(
app_id,
perm_type,
path,
self.system_mode
)
else:
success, message = libflatpak_query.remove_file_permissions(
app_id,
path,
None,
self.system_mode
)
if success:
# Refresh the current window
self.options_window.destroy()
self.on_app_options_clicked(None, app)
def _on_add_path(self, button, app_id, app, perm_type=None):
"""Handle add path button click"""
dialog = Gtk.Dialog(
title="Add Filesystem Path",
parent=self.options_window,
modal=True,
destroy_with_parent=True,
)
# Add buttons separately
dialog.add_button("Cancel", Gtk.ResponseType.CANCEL)
dialog.add_button("Add", Gtk.ResponseType.OK)
entry = Gtk.Entry()
entry.set_placeholder_text("Enter filesystem path")
dialog.vbox.pack_start(entry, True, True, 0)
dialog.show_all()
response = dialog.run()
if response == Gtk.ResponseType.OK:
path = entry.get_text()
if perm_type:
if perm_type == "persistent":
success, message = libflatpak_query.add_file_permissions(
app_id,
path,
"persistent",
self.system_mode
)
else:
success, message = libflatpak_query.add_permission_value(
app_id,
perm_type,
path,
self.system_mode
)
else:
success, message = libflatpak_query.add_file_permissions(
app_id,
path,
None,
self.system_mode
)
if success:
# Refresh the current window
self.options_window.destroy()
self.on_app_options_clicked(None, app)
message_type = Gtk.MessageType.INFO
else:
message_type = Gtk.MessageType.ERROR
if message:
error_dialog = Gtk.MessageDialog(
transient_for=None, # Changed from self
modal=True,
destroy_with_parent=True,
message_type=message_type,
buttons=Gtk.ButtonsType.OK,
text=message
)
error_dialog.run()
error_dialog.destroy()
dialog.destroy()
def _add_option(self, parent_box, label_text, description):
"""Helper method to add an individual option"""
row = Gtk.ListBoxRow(selectable=False)
hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=50)
row.add(hbox)
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
hbox.pack_start(vbox, True, True, 0)
label = Gtk.Label(label=label_text, xalign=0)
desc = Gtk.Label(label=description, xalign=0)
vbox.pack_start(label, True, True, 0)
vbox.pack_start(desc, True, True, 0)
switch = Gtk.Switch()
switch.props.valign = Gtk.Align.CENTER
hbox.pack_end(switch, False, True, 0)
parent_box.add(row)
return row, switch
def on_update_clicked(self, button, app):
"""Handle the Remove button click with removal options"""
details = app.get_details()

View file

@ -2227,7 +2227,7 @@
}
],
"query": "",
"processingTimeMs": 7,
"processingTimeMs": 8,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -3812,7 +3812,7 @@
}
],
"query": "",
"processingTimeMs": 6,
"processingTimeMs": 5,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -10295,7 +10295,7 @@
}
],
"query": "",
"processingTimeMs": 16,
"processingTimeMs": 19,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -12125,7 +12125,7 @@
}
],
"query": "",
"processingTimeMs": 4,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -13672,7 +13672,7 @@
}
],
"query": "",
"processingTimeMs": 2,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -14134,7 +14134,7 @@
}
],
"query": "",
"processingTimeMs": 3,
"processingTimeMs": 2,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -17220,7 +17220,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.freedesktop.Sdk/x86_64/24.08",
"updated_at": 1743670880,
"updated_at": 1743689559,
"arches": [
"x86_64",
"aarch64"
@ -18256,7 +18256,7 @@
}
],
"query": "",
"processingTimeMs": 3,
"processingTimeMs": 2,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -18992,7 +18992,7 @@
}
],
"query": "",
"processingTimeMs": 4,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -34567,7 +34567,7 @@
"project_license": "MPL-2.0",
"is_free_license": true,
"app_id": "info.cemu.Cemu",
"icon": "https://dl.flathub.org/media/info/cemu/Cemu/c2ee1c87418d1055b5efda32173e2eeb/icons/128x128/info.cemu.Cemu.png",
"icon": "https://dl.flathub.org/media/info/cemu/Cemu/87640c667068bea4e270477be92997a3/icons/128x128/info.cemu.Cemu.png",
"main_categories": "game",
"sub_categories": [
"Emulator"
@ -34581,7 +34581,7 @@
"verification_website": "cemu.info",
"verification_timestamp": "1679779906",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1742475302,
"updated_at": 1743689882,
"arches": [
"x86_64"
],
@ -35141,7 +35141,7 @@
"project_license": "GPL-3.0",
"is_free_license": true,
"app_id": "io.github.gopher64.gopher64",
"icon": "https://dl.flathub.org/media/io/github/gopher64.gopher64/364d7e1b846fb507371416d5721b81a2/icons/128x128/io.github.gopher64.gopher64.png",
"icon": "https://dl.flathub.org/media/io/github/gopher64.gopher64/459074e53a887ab9af8f43da34f41274/icons/128x128/io.github.gopher64.gopher64.png",
"main_categories": "game",
"sub_categories": [
"Emulator"
@ -35155,7 +35155,7 @@
"verification_website": null,
"verification_timestamp": "1699221966",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1742988449,
"updated_at": 1743677523,
"arches": [
"x86_64",
"aarch64"
@ -42183,7 +42183,7 @@
}
],
"query": "",
"processingTimeMs": 13,
"processingTimeMs": 12,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -52249,7 +52249,7 @@
"project_license": "LicenseRef-proprietary",
"is_free_license": false,
"app_id": "com.wireframesketcher.WireframeSketcher",
"icon": "https://dl.flathub.org/media/com/wireframesketcher/WireframeSketcher/63c0b229d59a15a516bb37f18c159575/icons/128x128/com.wireframesketcher.WireframeSketcher.png",
"icon": "https://dl.flathub.org/media/com/wireframesketcher/WireframeSketcher/08fc4f4f982674baf2112878c7fa2e3f/icons/128x128/com.wireframesketcher.WireframeSketcher.png",
"main_categories": "graphics",
"sub_categories": [
"VectorGraphics",
@ -52263,8 +52263,8 @@
"verification_login_is_organization": "false",
"verification_website": "wireframesketcher.com",
"verification_timestamp": "1728995861",
"runtime": "org.gnome.Platform/x86_64/47",
"updated_at": 1738504410,
"runtime": "org.gnome.Platform/x86_64/48",
"updated_at": 1743686066,
"arches": [
"x86_64"
],
@ -54042,7 +54042,7 @@
"project_license": "LicenseRef-proprietary=https://www.popcornfx.com/terms-and-conditions",
"is_free_license": false,
"app_id": "com.popcornfx.PopcornFXEditor",
"icon": "https://dl.flathub.org/media/com/popcornfx/PopcornFXEditor/bbc16f228a468060e76c2bcf1f055c11/icons/128x128/com.popcornfx.PopcornFXEditor.png",
"icon": "https://dl.flathub.org/media/com/popcornfx/PopcornFXEditor/8950264504787fde2a41a89e6cc59a6b/icons/128x128/com.popcornfx.PopcornFXEditor.png",
"main_categories": "graphics",
"sub_categories": [
"3DGraphics"
@ -54056,7 +54056,7 @@
"verification_website": "popcornfx.com",
"verification_timestamp": "1740390969",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1740561877,
"updated_at": 1743670231,
"arches": [
"x86_64"
],
@ -60274,7 +60274,7 @@
"project_license": "LicenseRef-proprietary",
"is_free_license": false,
"app_id": "com.wireframesketcher.WireframeSketcher",
"icon": "https://dl.flathub.org/media/com/wireframesketcher/WireframeSketcher/63c0b229d59a15a516bb37f18c159575/icons/128x128/com.wireframesketcher.WireframeSketcher.png",
"icon": "https://dl.flathub.org/media/com/wireframesketcher/WireframeSketcher/08fc4f4f982674baf2112878c7fa2e3f/icons/128x128/com.wireframesketcher.WireframeSketcher.png",
"main_categories": "graphics",
"sub_categories": [
"VectorGraphics",
@ -60288,8 +60288,8 @@
"verification_login_is_organization": "false",
"verification_website": "wireframesketcher.com",
"verification_timestamp": "1728995861",
"runtime": "org.gnome.Platform/x86_64/47",
"updated_at": 1738504410,
"runtime": "org.gnome.Platform/x86_64/48",
"updated_at": 1743686066,
"arches": [
"x86_64"
],
@ -63677,7 +63677,7 @@
"project_license": "AGPL-3.0-only",
"is_free_license": true,
"app_id": "org.signal.Signal",
"icon": "https://dl.flathub.org/media/org/signal/Signal/2566ff6b14efe7a97e76b251a00480c5/icons/128x128/org.signal.Signal.png",
"icon": "https://dl.flathub.org/media/org/signal/Signal/7958a28cf241175ba36c885f9577b5f3/icons/128x128/org.signal.Signal.png",
"main_categories": "network",
"sub_categories": [
"InstantMessaging",
@ -63692,7 +63692,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1743062228,
"updated_at": 1743667211,
"arches": [
"x86_64"
],
@ -69733,7 +69733,7 @@
}
],
"query": "",
"processingTimeMs": 3,
"processingTimeMs": 2,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -69918,7 +69918,7 @@
"project_license": "AGPL-3.0-only",
"is_free_license": true,
"app_id": "org.signal.Signal",
"icon": "https://dl.flathub.org/media/org/signal/Signal/2566ff6b14efe7a97e76b251a00480c5/icons/128x128/org.signal.Signal.png",
"icon": "https://dl.flathub.org/media/org/signal/Signal/7958a28cf241175ba36c885f9577b5f3/icons/128x128/org.signal.Signal.png",
"main_categories": "network",
"sub_categories": [
"InstantMessaging",
@ -69933,7 +69933,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1743062228,
"updated_at": 1743667211,
"arches": [
"x86_64"
],
@ -73160,7 +73160,7 @@
}
],
"query": "",
"processingTimeMs": 12,
"processingTimeMs": 11,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -74158,7 +74158,7 @@
}
],
"query": "",
"processingTimeMs": 2,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -76180,7 +76180,7 @@
"project_license": "LGPL-3.0-only",
"is_free_license": true,
"app_id": "org.tribler.Tribler",
"icon": "https://dl.flathub.org/media/org/tribler/Tribler/a2f52ea30ba1a4929dbb202e03d3e570/icons/128x128/org.tribler.Tribler.png",
"icon": "https://dl.flathub.org/media/org/tribler/Tribler/c0501155d99aa6ac0b25612ca1cb8d81/icons/128x128/org.tribler.Tribler.png",
"main_categories": "network",
"sub_categories": [
"P2P"
@ -76194,7 +76194,7 @@
"verification_website": "tribler.org",
"verification_timestamp": "1706271488",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1742060332,
"updated_at": 1743669027,
"arches": [
"x86_64",
"aarch64"
@ -78324,7 +78324,7 @@
"project_license": "BSD-3-Clause and LGPL-2.1+ and Apache-2.0 and IJG and MIT and GPL-2.0+ and ISC and OpenSSL and (MPL-1.1 or GPL-2.0 or LGPL-2.0)",
"is_free_license": true,
"app_id": "io.github.ungoogled_software.ungoogled_chromium",
"icon": "https://dl.flathub.org/media/io/github/ungoogled_software.ungoogled_chromium/39894c6a7477629d3ab86d3d95ef4aeb/icons/128x128/io.github.ungoogled_software.ungoogled_chromium.png",
"icon": "https://dl.flathub.org/media/io/github/ungoogled_software.ungoogled_chromium/7c63ca7b5da5a57b933e1111746511e1/icons/128x128/io.github.ungoogled_software.ungoogled_chromium.png",
"main_categories": "network",
"sub_categories": [
"WebBrowser",
@ -78340,7 +78340,7 @@
"verification_website": null,
"verification_timestamp": "1713606111",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1743133926,
"updated_at": 1743673160,
"arches": [
"x86_64",
"aarch64"
@ -79779,7 +79779,7 @@
"project_license": "LicenseRef-proprietary=https://wavebox.io/eula",
"is_free_license": false,
"app_id": "io.wavebox.Wavebox",
"icon": "https://dl.flathub.org/media/io/wavebox/Wavebox/2b3f6b5b0cd051bf329fad85e03875cc/icons/128x128/io.wavebox.Wavebox.png",
"icon": "https://dl.flathub.org/media/io/wavebox/Wavebox/7456cfd08230164fd31c4dc164e96a2a/icons/128x128/io.wavebox.Wavebox.png",
"main_categories": "network",
"sub_categories": [
"WebBrowser"
@ -79793,7 +79793,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.freedesktop.Platform/x86_64/21.08",
"updated_at": 1742817444,
"updated_at": 1743674289,
"arches": [
"x86_64"
],
@ -79928,7 +79928,7 @@
}
],
"query": "",
"processingTimeMs": 6,
"processingTimeMs": 7,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -79959,7 +79959,7 @@
"project_license": "BSD-3-Clause and LGPL-2.1+ and Apache-2.0 and IJG and MIT and GPL-2.0+ and ISC and OpenSSL and (MPL-1.1 or GPL-2.0 or LGPL-2.0)",
"is_free_license": true,
"app_id": "io.github.ungoogled_software.ungoogled_chromium",
"icon": "https://dl.flathub.org/media/io/github/ungoogled_software.ungoogled_chromium/39894c6a7477629d3ab86d3d95ef4aeb/icons/128x128/io.github.ungoogled_software.ungoogled_chromium.png",
"icon": "https://dl.flathub.org/media/io/github/ungoogled_software.ungoogled_chromium/7c63ca7b5da5a57b933e1111746511e1/icons/128x128/io.github.ungoogled_software.ungoogled_chromium.png",
"main_categories": "network",
"sub_categories": [
"WebBrowser",
@ -79975,7 +79975,7 @@
"verification_website": null,
"verification_timestamp": "1713606111",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1743133926,
"updated_at": 1743673160,
"arches": [
"x86_64",
"aarch64"
@ -82634,7 +82634,7 @@
}
],
"query": "",
"processingTimeMs": 2,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -84203,7 +84203,7 @@
}
],
"query": "",
"processingTimeMs": 7,
"processingTimeMs": 6,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -84436,7 +84436,7 @@
"project_license": "MIT",
"is_free_license": true,
"app_id": "com.super_productivity.SuperProductivity",
"icon": "https://dl.flathub.org/media/com/super_productivity/SuperProductivity/53bb571f02820641926d8f042929a3c8/icons/128x128/com.super_productivity.SuperProductivity.png",
"icon": "https://dl.flathub.org/media/com/super_productivity/SuperProductivity/be0a31f47f3837c8b137110fea0bb11c/icons/128x128/com.super_productivity.SuperProductivity.png",
"main_categories": "office",
"sub_categories": [
"ProjectManagement"
@ -84450,7 +84450,7 @@
"verification_website": "super-productivity.com",
"verification_timestamp": "1733677286",
"runtime": "org.freedesktop.Platform/x86_64/24.08",
"updated_at": 1741964323,
"updated_at": 1743686508,
"arches": [
"x86_64"
],
@ -85457,7 +85457,7 @@
"verification_website": null,
"verification_timestamp": "1681472057",
"runtime": "org.kde.Platform/x86_64/6.8",
"updated_at": 1743633547,
"updated_at": 1743677378,
"arches": [
"x86_64",
"aarch64"
@ -85666,7 +85666,7 @@
"project_license": "Zlib",
"is_free_license": true,
"app_id": "com.strlen.TreeSheets",
"icon": "https://dl.flathub.org/media/com/strlen/TreeSheets/a56dee5995e3e5b4742dfc3313966697/icons/128x128/com.strlen.TreeSheets.png",
"icon": "https://dl.flathub.org/media/com/strlen/TreeSheets/fa00efbb2fc13f353508162cb663dba9/icons/128x128/com.strlen.TreeSheets.png",
"main_categories": "office",
"sub_categories": [
"Spreadsheet",
@ -85682,7 +85682,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.freedesktop.Platform/x86_64/23.08",
"updated_at": 1743492010,
"updated_at": 1743674544,
"arches": [
"x86_64",
"aarch64"
@ -87983,7 +87983,7 @@
"verification_website": null,
"verification_timestamp": null,
"runtime": "org.gnome.Platform/x86_64/46",
"updated_at": 1743647957,
"updated_at": 1743681287,
"arches": [
"x86_64",
"aarch64"
@ -89321,7 +89321,7 @@
}
],
"query": "",
"processingTimeMs": 2,
"processingTimeMs": 3,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -90915,7 +90915,7 @@
}
],
"query": "",
"processingTimeMs": 3,
"processingTimeMs": 2,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,
@ -93377,7 +93377,7 @@
}
],
"query": "",
"processingTimeMs": 4,
"processingTimeMs": 5,
"hitsPerPage": 250,
"page": 1,
"totalPages": 1,