diff --git a/data/gresource.xml b/data/gresource.xml index 3baf25c1..326a92bc 100644 --- a/data/gresource.xml +++ b/data/gresource.xml @@ -4,6 +4,9 @@ Application.css + icons/usb.svg + icons/usb.svg + icons/screencast.svg icons/screencast.svg diff --git a/data/icons/usb.svg b/data/icons/usb.svg new file mode 100644 index 00000000..abf7fc36 --- /dev/null +++ b/data/icons/usb.svg @@ -0,0 +1,2 @@ + +image/svg+xml diff --git a/data/pantheon.portal b/data/pantheon.portal index b9de94e3..91020daf 100644 --- a/data/pantheon.portal +++ b/data/pantheon.portal @@ -1,4 +1,4 @@ [portal] DBusName=org.freedesktop.impl.portal.desktop.pantheon -Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Background;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Wallpaper;org.freedesktop.impl.portal.ScreenCast +Interfaces=org.freedesktop.impl.portal.Access;org.freedesktop.impl.portal.AppChooser;org.freedesktop.impl.portal.Background;org.freedesktop.impl.portal.Screenshot;org.freedesktop.impl.portal.Usb;org.freedesktop.impl.portal.Wallpaper;org.freedesktop.impl.portal.ScreenCast UseIn=pantheon diff --git a/po/POTFILES b/po/POTFILES index e43f71dc..b3f60bec 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -10,3 +10,5 @@ src/Background/Portal.vala src/ScreenCast/Dialog.vala src/ScreenCast/MonitorTracker/Interface.vala src/Screenshot/SetupDialog.vala +src/Usb/Dialog.vala +src/Usb/Portal.vala diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index 9dc7bdc4..bbb811fe 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -54,7 +54,20 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { public enum ResponseType { ALLOW, CANCEL, - DELETE_EVENT + DELETE_EVENT; + + // Convert to response ID expected by portal backends + public uint32 to_id () { + switch (this) { + case ALLOW: + return 0; + case CANCEL: + return 1; + default: + case DELETE_EVENT: + return 2; + } + } } /** diff --git a/src/Usb/Dialog.vala b/src/Usb/Dialog.vala new file mode 100644 index 00000000..8f629e59 --- /dev/null +++ b/src/Usb/Dialog.vala @@ -0,0 +1,44 @@ +/* + * SPDX-FileCopyrigthText: 2026 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +[DBus (name = "org.freedesktop.impl.portal.Request")] +public class Usb.Dialog : PortalDialog { + // The ID used to register this dialog on the DBusConnection + public uint register_id { get; set; default = 0; } + + // The ID of the app sending the request + public string app_id { get; construct; } + + public string reason { + set { + secondary_text = _("It provided the following reason, ā€œ%sā€").printf (value); + } + } + + public Dialog (string app_id) { + Object (app_id: app_id); + } + + construct { + default_height = -1; + title = _("An application wants to access the following USB devices"); + secondary_icon = new ThemedIcon ("emblem-portal-usb"); + secondary_text = _("It did not provide a reason for this request."); + + if (app_id != "") { + var app_info = new DesktopAppInfo (app_id + ".desktop"); + if (app_info != null) { + primary_icon = app_info.get_icon (); + title = _("ā€œ%sā€ wants to access the following USB devices").printf (app_info.get_display_name ()); + } + } + + } + + [DBus (name = "Close")] + public void on_close () throws DBusError, IOError { + response (DELETE_EVENT); + } +} diff --git a/src/Usb/Portal.vala b/src/Usb/Portal.vala new file mode 100644 index 00000000..5020d77b --- /dev/null +++ b/src/Usb/Portal.vala @@ -0,0 +1,65 @@ +/* + * SPDX-FileCopyrigthText: 2026 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +[DBus (name = "org.freedesktop.impl.portal.Usb")] +public class Usb.Portal : Object { + private DBusConnection connection; + + public Portal (DBusConnection connection) { + this.connection = connection; + } + + [DBus (name = "AcquireDevices")] + public async void acquire_devices ( + ObjectPath handle, + string parent_window, + string app_id, + // G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a(sa{sv})")); + // IN devices a(sa{sv}a{sv}), + HashTable options, + out uint response, + out HashTable results + ) throws DBusError, IOError { + var dialog = new Dialog (app_id) { + parent_handle = parent_window + }; + + if ("reason" in options) { + dialog.reason = options["reason"].get_string (); + } + + try { + dialog.register_id = connection.register_object (handle, dialog); + } catch (Error e) { + critical (e.message); + } + + var _results = new HashTable (str_hash, str_equal); + uint _response = 2; + + dialog.response.connect ((response) => { + switch (response) { + case ALLOW: + + break; + default: + break; + } + + _response = response.to_id (); + + acquire_devices.callback (); + }); + + dialog.present (); + yield; + + connection.unregister_object (dialog.register_id); + dialog.destroy (); + + results = _results; + response = _response; + } +} diff --git a/src/XdgDesktopPortalPantheon.vala b/src/XdgDesktopPortalPantheon.vala index 1569817e..b96238d4 100644 --- a/src/XdgDesktopPortalPantheon.vala +++ b/src/XdgDesktopPortalPantheon.vala @@ -44,6 +44,9 @@ private void on_bus_acquired (DBusConnection connection, string name) { connection.register_object ("/org/freedesktop/portal/desktop", new Screenshot.Portal (connection)); debug ("Screenshot Portal registered!"); + connection.register_object ("/org/freedesktop/portal/desktop", new Usb.Portal (connection)); + debug ("USB Portal registered!"); + connection.register_object ("/org/freedesktop/portal/desktop", new Wallpaper.Portal (connection)); debug ("Wallpaper Portal registered!"); diff --git a/src/meson.build b/src/meson.build index 843990a7..1dc9bd2f 100644 --- a/src/meson.build +++ b/src/meson.build @@ -18,6 +18,8 @@ executable( 'Screenshot/Portal.vala', 'Screenshot/SetupDialog.vala', 'Screenshot/Utils.vala', + 'Usb' / 'Dialog.vala', + 'Usb' / 'Portal.vala', 'Wallpaper/Portal.vala', configure_file(input: 'Config.vala.in', output: '@BASENAME@', configuration: conf_data), 'DesktopIntegration.vala',