From 811a2a90b2d4efac5c75fd58247836b5b7a9f945 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 13 Feb 2026 09:21:31 -0800 Subject: [PATCH 1/3] Access: create custom location dialog --- po/POTFILES | 1 + src/Access/LocationDialog.vala | 27 +++++++ src/Access/Portal.vala | 127 ++++++++++++++++++--------------- src/AppChooser/Dialog.vala | 1 + src/PortalDialog.vala | 1 - src/ScreenCast/Dialog.vala | 1 + src/meson.build | 1 + 7 files changed, 102 insertions(+), 57 deletions(-) create mode 100644 src/Access/LocationDialog.vala diff --git a/po/POTFILES b/po/POTFILES index e43f71dc..ff52ebea 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -1,5 +1,6 @@ src/XdgDesktopPortalPantheon.vala src/ExternalWindow.vala +src/Access/LocationDialog.vala src/Access/Portal.vala src/Access/Dialog.vala src/AppChooser/Portal.vala diff --git a/src/Access/LocationDialog.vala b/src/Access/LocationDialog.vala new file mode 100644 index 00000000..49c94999 --- /dev/null +++ b/src/Access/LocationDialog.vala @@ -0,0 +1,27 @@ +/* + * SPDX-FileCopyrightText: 2026 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +[DBus (name = "org.freedesktop.impl.portal.Request")] +public class Access.LocationDialog : PortalDialog { + public string app_id { get; construct; } + + public LocationDialog (string app_id) { + Object (app_id: app_id); + } + + construct { + title = _("An application wants to access your location"); + secondary_text = _("Permissions can be changed in Location Settings…"); + secondary_icon = new ThemedIcon ("preferences-system-privacy-location"); + + 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 your location").printf (app_info.get_display_name ()); + } + } + } +} diff --git a/src/Access/Portal.vala b/src/Access/Portal.vala index 6337469c..5b86bd5b 100644 --- a/src/Access/Portal.vala +++ b/src/Access/Portal.vala @@ -25,70 +25,85 @@ public class Access.Portal : Object { Dialog.ButtonAction action = Dialog.ButtonAction.SUGGESTED; string icon = "dialog-information"; uint register_id = 0; - - if ("destructive" in options && options["destructive"].get_boolean ()) { - action = Dialog.ButtonAction.DESTRUCTIVE; - } + var _results = new HashTable (str_hash, str_equal); + var _response = 2; if ("icon" in options) { // elementary HIG use non-symbolic icon, while portals ask for symbolic ones. icon = options["icon"].get_string ().replace ("-symbolic", ""); } - var dialog = new Dialog (action, app_id, parent_window, icon) { - primary_text = title, - secondary_text = sub_title, - body = body - }; - - if ("modal" in options) { - dialog.modal = options["modal"].get_boolean (); - } - - if ("deny_label" in options) { - dialog.deny_label = options["deny_label"].get_string (); - } - - if ("grant_label" in options) { - dialog.grant_label = options["grant_label"].get_string (); - } - - if ("choices" in options) { - var choices_iter = options["choices"].iterator (); - Variant choice_variant; + // if (icon == "find-location") { + var dialog = new LocationDialog (app_id) { + parent_handle = parent_window + }; - while ((choice_variant = choices_iter.next_value ()) != null) { - dialog.add_choice (new Choice.from_variant (choice_variant)); - } - } - - var _results = new HashTable (str_hash, str_equal); - var _response = 2; - - dialog.response.connect ((id) => { - switch (id) { - case Gtk.ResponseType.OK: - var choices_builder = new VariantBuilder (new VariantType ("a(ss)")); - - dialog.get_choices ().foreach ((choice) => { - choices_builder.add ("(ss)", choice.name, choice.selected); - }); - - _results["choices"] = choices_builder.end (); - _response = 0; - break; - - case Gtk.ResponseType.CANCEL: + dialog.response.connect ((response) => { + if (response == CANCEL) { _response = 1; - break; - - case Gtk.ResponseType.DELETE_EVENT: - _response = 2; - break; - } - - access_dialog.callback (); - }); + } else { + _response = 0; + } + + access_dialog.callback (); + }); + // } + + // if ("destructive" in options && options["destructive"].get_boolean ()) { + // action = Dialog.ButtonAction.DESTRUCTIVE; + // } + + // var dialog = new Dialog (action, app_id, parent_window, icon) { + // primary_text = title, + // secondary_text = sub_title, + // body = body + // }; + + // if ("modal" in options) { + // dialog.modal = options["modal"].get_boolean (); + // } + + // if ("deny_label" in options) { + // dialog.deny_label = options["deny_label"].get_string (); + // } + + // if ("grant_label" in options) { + // dialog.grant_label = options["grant_label"].get_string (); + // } + + // if ("choices" in options) { + // var choices_iter = options["choices"].iterator (); + // Variant choice_variant; + + // while ((choice_variant = choices_iter.next_value ()) != null) { + // dialog.add_choice (new Choice.from_variant (choice_variant)); + // } + // } + + // dialog.response.connect ((id) => { + // switch (id) { + // case Gtk.ResponseType.OK: + // var choices_builder = new VariantBuilder (new VariantType ("a(ss)")); + + // dialog.get_choices ().foreach ((choice) => { + // choices_builder.add ("(ss)", choice.name, choice.selected); + // }); + + // _results["choices"] = choices_builder.end (); + // _response = 0; + // break; + + // case Gtk.ResponseType.CANCEL: + // _response = 1; + // break; + + // case Gtk.ResponseType.DELETE_EVENT: + // _response = 2; + // break; + // } + + // access_dialog.callback (); + // }); try { register_id = connection.register_object (handle, dialog); diff --git a/src/AppChooser/Dialog.vala b/src/AppChooser/Dialog.vala index 70309027..a4778bf1 100644 --- a/src/AppChooser/Dialog.vala +++ b/src/AppChooser/Dialog.vala @@ -94,6 +94,7 @@ public class AppChooser.Dialog : PortalDialog { allow_label = _("Open"); content = frame; + default_height = 425; listbox.row_activated.connect ((row) => { choiced (((AppChooser.AppButton) row).app_id); diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index e63bca71..86d719af 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -100,7 +100,6 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { child = toolbarview; - default_height = 425; default_width = 325; default_widget = allow_button; modal = true; diff --git a/src/ScreenCast/Dialog.vala b/src/ScreenCast/Dialog.vala index de96a0c4..47c59920 100644 --- a/src/ScreenCast/Dialog.vala +++ b/src/ScreenCast/Dialog.vala @@ -69,6 +69,7 @@ public class ScreenCast.Dialog : PortalDialog { }; content = frame; + default_height = 425; allow_label = _("Share"); diff --git a/src/meson.build b/src/meson.build index 843990a7..c14e4194 100644 --- a/src/meson.build +++ b/src/meson.build @@ -2,6 +2,7 @@ executable( meson.project_name(), 'Access/Choice.vala', 'Access/Dialog.vala', + 'Access/LocationDialog.vala', 'Access/Portal.vala', 'AppChooser/AppButton.vala', 'AppChooser/Dialog.vala', From cc0dcc6473b301ab059d482a8e8760d8bf9860f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 5 Mar 2026 09:03:14 -0800 Subject: [PATCH 2/3] Add custom circle icon --- data/gresource.xml | 3 +++ data/icons/location.svg | 43 ++++++++++++++++++++++++++++++++++ src/Access/LocationDialog.vala | 7 +++++- src/Access/Portal.vala | 14 +++++++---- src/PortalDialog.vala | 8 ++++--- 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 data/icons/location.svg diff --git a/data/gresource.xml b/data/gresource.xml index 3baf25c1..197825b7 100644 --- a/data/gresource.xml +++ b/data/gresource.xml @@ -4,6 +4,9 @@ Application.css + icons/location.svg + icons/location.svg + icons/screencast.svg icons/screencast.svg diff --git a/data/icons/location.svg b/data/icons/location.svg new file mode 100644 index 00000000..6bbabff6 --- /dev/null +++ b/data/icons/location.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/Access/LocationDialog.vala b/src/Access/LocationDialog.vala index 49c94999..2a5adb39 100644 --- a/src/Access/LocationDialog.vala +++ b/src/Access/LocationDialog.vala @@ -14,7 +14,7 @@ public class Access.LocationDialog : PortalDialog { construct { title = _("An application wants to access your location"); secondary_text = _("Permissions can be changed in Location Settings…"); - secondary_icon = new ThemedIcon ("preferences-system-privacy-location"); + secondary_icon = new ThemedIcon ("emblem-portal-location"); if (app_id != "") { var app_info = new DesktopAppInfo (app_id + ".desktop"); @@ -24,4 +24,9 @@ public class Access.LocationDialog : PortalDialog { } } } + + [DBus (name = "Close")] + public void on_close () throws DBusError, IOError { + response (DELETE_EVENT); + } } diff --git a/src/Access/Portal.vala b/src/Access/Portal.vala index 5b86bd5b..76273636 100644 --- a/src/Access/Portal.vala +++ b/src/Access/Portal.vala @@ -39,10 +39,16 @@ public class Access.Portal : Object { }; dialog.response.connect ((response) => { - if (response == CANCEL) { - _response = 1; - } else { - _response = 0; + switch (response) { + case ALLOW: + _response = 0; + break; + case CANCEL: + _response = 1; + break; + case DELETE_EVENT: + _response = 2; + break; } access_dialog.callback (); diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index 86d719af..85c26bed 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -46,7 +46,8 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { public enum ResponseType { ALLOW, - CANCEL + CANCEL, + DELETE_EVENT } /** @@ -122,8 +123,9 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { ((Gtk.Widget) this).realize.connect (on_realize); - allow_button.clicked.connect (() => response (ResponseType.ALLOW)); - cancel_button.clicked.connect (() => response (ResponseType.CANCEL)); + allow_button.clicked.connect (() => response (ALLOW)); + cancel_button.clicked.connect (() => response (CANCEL)); + close_request.connect (() => { response (DELETE_EVENT); }); } private void on_realize () { From a1455f1e2e87a4fc45da53b6212edfa0d11f1032 Mon Sep 17 00:00:00 2001 From: Ryo Nakano Date: Sun, 2 Aug 2026 06:37:51 +0900 Subject: [PATCH 3/3] Location dialog suggestion (#193) --- src/Access/Portal.vala | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Access/Portal.vala b/src/Access/Portal.vala index e262aa4f..820faa38 100644 --- a/src/Access/Portal.vala +++ b/src/Access/Portal.vala @@ -32,13 +32,13 @@ public class Access.Portal : Object { }; if ("icon" in options) { + // elementary HIG use non-symbolic icon, while portals ask for symbolic ones. var icon = options["icon"].get_string ().replace ("-symbolic", ""); if (icon == "find-location") { dialog = new LocationDialog (app_id) { parent_handle = parent_window }; } else { - // elementary HIG use non-symbolic icon, while portals ask for symbolic ones. dialog.secondary_icon = new ThemedIcon (icon); } } @@ -66,9 +66,6 @@ public class Access.Portal : Object { dialog.allow_label = options["grant_label"].get_string (); } - var _results = new HashTable (str_hash, str_equal); - uint32 _response = 2; - if ("choices" in options) { var choices_iter = options["choices"].iterator (); Variant choice_variant; @@ -78,6 +75,9 @@ public class Access.Portal : Object { } } + var _results = new HashTable (str_hash, str_equal); + uint32 _response = 2; + dialog.response.connect ((response) => { switch (response) { case ALLOW: