From 8e0dca9f530564a61d74cd593553bcb0878cb38d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 13 Feb 2026 08:47:36 -0800 Subject: [PATCH 1/7] Access: use PortalDialog --- src/Access/Dialog.vala | 96 ++++-------------------------------------- src/Access/Portal.vala | 36 +++++++++------- src/PortalDialog.vala | 34 +++++++++++++-- 3 files changed, 60 insertions(+), 106 deletions(-) diff --git a/src/Access/Dialog.vala b/src/Access/Dialog.vala index 58b32d29..af9631a6 100644 --- a/src/Access/Dialog.vala +++ b/src/Access/Dialog.vala @@ -4,30 +4,7 @@ */ [DBus (name = "org.freedesktop.impl.portal.Request")] -public class Access.Dialog : Granite.MessageDialog, PantheonWayland.ExtendedBehavior { - public enum ButtonAction { - SUGGESTED, - DESTRUCTIVE - } - - public ButtonAction action { get; construct; } - - public string parent_window { get; construct; } - - public string app_id { get; construct; } - - public string deny_label { - set { - deny_button.label = value; - } - } - - public string grant_label { - set { - grant_button.label = value; - } - } - +public class Access.Dialog : PortalDialog { public string body { set { if (value != "") { @@ -36,77 +13,20 @@ public class Access.Dialog : Granite.MessageDialog, PantheonWayland.ExtendedBeha } } - private unowned Gtk.Button grant_button; - private unowned Gtk.Button deny_button; private List choices; - - public Dialog (ButtonAction action, string app_id, string parent_window, string icon) { - Object ( - action: action, - app_id: app_id, - parent_window: parent_window, - image_icon: new ThemedIcon (icon), - buttons: Gtk.ButtonsType.NONE - ); - } + private Granite.Box? custom_bin = null; construct { - resizable = false; - modal = true; - choices = new List (); - - if (app_id != "") { - badge_icon = new DesktopAppInfo (app_id + ".desktop").get_icon (); - } - - deny_button = add_button (_("Deny Access"), Gtk.ResponseType.CANCEL) as Gtk.Button; - grant_button = add_button (_("Grant Access"), Gtk.ResponseType.OK) as Gtk.Button; - - if (action == ButtonAction.SUGGESTED) { - grant_button.add_css_class (Granite.CssClass.SUGGESTED); - default_widget = grant_button; - } else { - grant_button.add_css_class (Granite.CssClass.DESTRUCTIVE); - default_widget = deny_button; - } - - custom_bin.orientation = Gtk.Orientation.VERTICAL; - custom_bin.spacing = 6; - - if (parent_window == "") { - child.realize.connect (() => { - connect_to_shell (); - make_centered (); - set_keep_above (); - }); - } - } - - public override void show () { - ((Gtk.Widget) base).realize (); - - unowned var toplevel = (Gdk.Toplevel) get_surface (); - - if (parent_window != "") { - try { - ExternalWindow.from_handle (parent_window).set_parent_of (toplevel); - } catch (Error e) { - warning ("Failed to associate portal window with parent '%s': %s", parent_window, e.message); - } - } - - base.show (); - toplevel.focus (Gdk.CURRENT_TIME); - } - - public override void close () { - response (Gtk.ResponseType.CANCEL); - base.close (); } [DBus (visible = false)] public void add_choice (Choice choice) { + if (custom_bin == null) { + custom_bin = new Granite.Box (VERTICAL, HALF); + content = custom_bin; + } + choices.append (choice); custom_bin.append (choice); } @@ -118,6 +38,6 @@ public class Access.Dialog : Granite.MessageDialog, PantheonWayland.ExtendedBeha [DBus (name = "Close")] public void on_close () throws DBusError, IOError { - response (Gtk.ResponseType.DELETE_EVENT); + response (DELETE_EVENT); } } diff --git a/src/Access/Portal.vala b/src/Access/Portal.vala index 6337469c..35891337 100644 --- a/src/Access/Portal.vala +++ b/src/Access/Portal.vala @@ -22,35 +22,41 @@ public class Access.Portal : Object { out uint32 response, out HashTable results ) throws DBusError, IOError { - Dialog.ButtonAction action = Dialog.ButtonAction.SUGGESTED; - string icon = "dialog-information"; uint register_id = 0; + var dialog = new Dialog () { + title = title, + secondary_text = sub_title, + body = body, + parent_handle = parent_window + }; + + if (app_id != "") { + dialog.primary_icon = new DesktopAppInfo (app_id + ".desktop").get_icon (); + } else { + // non-sandboxed access must be the system itself + dialog.primary_icon = new ThemedIcon ("io.elementary.settings"); + } + if ("destructive" in options && options["destructive"].get_boolean ()) { - action = Dialog.ButtonAction.DESTRUCTIVE; + dialog.action_type = DESTRUCTIVE; } if ("icon" in options) { // elementary HIG use non-symbolic icon, while portals ask for symbolic ones. - icon = options["icon"].get_string ().replace ("-symbolic", ""); + dialog.secondary_icon = new ThemedIcon (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 (); + dialog.cancel_label = options["deny_label"].get_string (); } if ("grant_label" in options) { - dialog.grant_label = options["grant_label"].get_string (); + dialog.allow_label = options["grant_label"].get_string (); } if ("choices" in options) { @@ -67,7 +73,7 @@ public class Access.Portal : Object { dialog.response.connect ((id) => { switch (id) { - case Gtk.ResponseType.OK: + case ALLOW: var choices_builder = new VariantBuilder (new VariantType ("a(ss)")); dialog.get_choices ().foreach ((choice) => { @@ -78,11 +84,11 @@ public class Access.Portal : Object { _response = 0; break; - case Gtk.ResponseType.CANCEL: + case CANCEL: _response = 1; break; - case Gtk.ResponseType.DELETE_EVENT: + case DELETE_EVENT: _response = 2; break; } diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index e63bca71..184ee8e0 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -27,7 +27,7 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { /** * The child widget for the content area */ - public Gtk.Widget content { get; set; } + public Gtk.Widget content { get; set; default = null; } /** * The label of the button which denies access @@ -44,9 +44,17 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { */ public bool form_valid { get; set; default = true; } + public ActionType action_type { get; set; default = SUGGESTED; } + + public enum ActionType { + SUGGESTED, + DESTRUCTIVE + } + public enum ResponseType { ALLOW, - CANCEL + CANCEL, + DELETE_EVENT } /** @@ -100,7 +108,6 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { child = toolbarview; - default_height = 425; default_width = 325; default_widget = allow_button; modal = true; @@ -121,10 +128,31 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { bind_property ("allow-label", allow_button, "label"); bind_property ("cancel-label", cancel_button, "label"); + notify["action-type"].connect (() => { + if (action_type == SUGGESTED) { + allow_button.add_css_class (Granite.CssClass.SUGGESTED); + allow_button.receives_default = true; + default_widget = allow_button; + } else { + allow_button.add_css_class (Granite.CssClass.DESTRUCTIVE); + cancel_button.receives_default = true; + default_widget = cancel_button; + } + }); + + notify["content"].connect (() => { + if (content != null) { + default_height = 425; + } else { + default_height = -1; + } + }); + ((Gtk.Widget) this).realize.connect (on_realize); allow_button.clicked.connect (() => response (ResponseType.ALLOW)); cancel_button.clicked.connect (() => response (ResponseType.CANCEL)); + close_request.connect (() => { response (ResponseType.CANCEL); }); } private void on_realize () { From 81f854152a3aebcdaf15741fc795f109feb912db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 13 Feb 2026 08:52:24 -0800 Subject: [PATCH 2/7] Don't try to be too clever --- src/AppChooser/Dialog.vala | 1 + src/PortalDialog.vala | 8 -------- src/ScreenCast/Dialog.vala | 1 + 3 files changed, 2 insertions(+), 8 deletions(-) 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 184ee8e0..411972c6 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -140,14 +140,6 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { } }); - notify["content"].connect (() => { - if (content != null) { - default_height = 425; - } else { - default_height = -1; - } - }); - ((Gtk.Widget) this).realize.connect (on_realize); allow_button.clicked.connect (() => response (ResponseType.ALLOW)); 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"); From 672b6815ba1a9e5aa16783f8253a69258b8605b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 13 Feb 2026 14:06:31 -0800 Subject: [PATCH 3/7] Update Portal.vala Co-authored-by: Ryo Nakano --- src/Access/Portal.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Access/Portal.vala b/src/Access/Portal.vala index 35891337..e000bb93 100644 --- a/src/Access/Portal.vala +++ b/src/Access/Portal.vala @@ -44,7 +44,7 @@ public class Access.Portal : Object { if ("icon" in options) { // elementary HIG use non-symbolic icon, while portals ask for symbolic ones. - dialog.secondary_icon = new ThemedIcon (options["icon"].get_string ().replace ("-symbolic", "")); + dialog.secondary_icon = new ThemedIcon (options["icon"].get_string ().replace ("-symbolic", "")); } if ("modal" in options) { From 448c02a947dc756551eca1141f1e947414771709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Fri, 13 Feb 2026 14:09:05 -0800 Subject: [PATCH 4/7] Update PortalDialog.vala --- src/PortalDialog.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index 411972c6..5111cd09 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -27,7 +27,7 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { /** * The child widget for the content area */ - public Gtk.Widget content { get; set; default = null; } + public Gtk.Widget content { get; set; } /** * The label of the button which denies access From fc52c6f32ff9e823b45392a4690708e4d48b94fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Mon, 16 Feb 2026 08:27:40 -0800 Subject: [PATCH 5/7] explicitly set receives default false --- src/PortalDialog.vala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index 5111cd09..f5bfcefa 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -131,10 +131,12 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { notify["action-type"].connect (() => { if (action_type == SUGGESTED) { allow_button.add_css_class (Granite.CssClass.SUGGESTED); + cancel_button.receives_default = false; allow_button.receives_default = true; default_widget = allow_button; } else { allow_button.add_css_class (Granite.CssClass.DESTRUCTIVE); + allow_button.receives_default = false; cancel_button.receives_default = true; default_widget = cancel_button; } From b141d9f7e4139aa0742e0d8b5de58c8c5820a4ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Wed, 4 Mar 2026 11:01:54 -0800 Subject: [PATCH 6/7] Update PortalDialog.vala --- src/PortalDialog.vala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index f5bfcefa..4080a20a 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -146,7 +146,7 @@ public class PortalDialog : Gtk.Window, PantheonWayland.ExtendedBehavior { allow_button.clicked.connect (() => response (ResponseType.ALLOW)); cancel_button.clicked.connect (() => response (ResponseType.CANCEL)); - close_request.connect (() => { response (ResponseType.CANCEL); }); + close_request.connect (() => { response (DELETE_EVENT); }); } private void on_realize () { From 694f36686b12ce08490e5229e52c7a5fabcc7375 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danielle=20For=C3=A9?= Date: Thu, 5 Mar 2026 08:29:04 -0800 Subject: [PATCH 7/7] Implicit namespace --- src/PortalDialog.vala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/PortalDialog.vala b/src/PortalDialog.vala index 4080a20a..9dc7bdc4 100644 --- a/src/PortalDialog.vala +++ b/src/PortalDialog.vala @@ -144,8 +144,8 @@ 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); }); }