Skip to content

Commit

Permalink
Access: Restructure Code (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
Marukesu authored Dec 1, 2021
1 parent a718785 commit e74df0e
Show file tree
Hide file tree
Showing 4 changed files with 167 additions and 137 deletions.
59 changes: 59 additions & 0 deletions src/Access/Choice.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* SPDX-FileCopyrightText: 2021 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

public class Access.Choice : Gtk.Box {
public Variant? options { get; construct; }
public string label { get; set; }
public string selected { get; set; }

public Choice.from_variant (Variant variant) requires (
variant.is_of_type (new VariantType ("(ssa(ss)s)"))
) {
string id, label, selected;
Variant? options;

variant.get ("(ss@a(ss)s)", out id, out label, out options, out selected);

Object (name: id, label: label, options: options, selected: selected);
}

construct {
orientation = Gtk.Orientation.VERTICAL;
halign = Gtk.Align.START;
spacing = 6;

var label = new Gtk.Label (label);
bind_property ("label", label, "label", BindingFlags.DEFAULT);
add (label);

if (options.n_children () == 0) {
var check = new Gtk.CheckButton ();
bind_property (
"selected", check, "active", BindingFlags.BIDIRECTIONAL,
(b, s, ref t) => {
t.set_boolean (bool.parse ((string) s));
return true;
},
(b, s, ref t) => {
t.set_string (((bool) s).to_string ());
return true;
}
);

add (check);
} else {
var combo = new Gtk.ComboBoxText ();
var iter = options.iterator ();
string key, val;

while (iter.next ("(ss)", out key, out val)) {
combo.append (key, val);
}

bind_property ("selected", combo, "active-id", BindingFlags.BIDIRECTIONAL);
add (combo);
}
}
}
172 changes: 59 additions & 113 deletions src/Access/Dialog.vala
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
/*
*
*
* SPDX-FileCopyrightText: 2021 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

[DBus (name = "org.freedesktop.impl.portal.Request")]
public class Access.Dialog : Granite.MessageDialog {
private DBusConnection connection;
private string parent_handle;
private uint register_id;
public uint register_id { get; set; default = 0; }

private Gtk.Button grant_button;
private Gtk.Button deny_button;
private Gtk.Box box;
public string parent_window { get; construct; }

public string app_id { get; construct; }

public string deny_label {
set {
Expand All @@ -25,134 +23,82 @@ public class Access.Dialog : Granite.MessageDialog {
}
}

public HashTable<unowned string, string> choices { get; private set; }

public Dialog (
DBusConnection conn,
ObjectPath handle,
string app_id,
string parent_window,
string title,
string sub_title,
string body
) {
Object (
primary_text: title,
secondary_text: sub_title,
image_icon : new ThemedIcon ("dialog-information"),
buttons: Gtk.ButtonsType.NONE,
resizable: false,
skip_taskbar_hint: true
);

connection = conn;
try {
register_id = connection.register_object<Dialog> (handle, this);
} catch (Error e) {
critical (e.message);
}

if (body != "") {
box.pack_start (new Gtk.Label (body), false, false);
public string body {
set {
if (value != "") {
secondary_text += "\n\n" + value;
}
}
}

realize ();
private Gtk.Button grant_button;
private Gtk.Button deny_button;
private List<Choice> choices;
private Gtk.Box box;

if (parent_window != "") {
var parent = ExternalWindow.from_handle (parent_window);
if (parent == null) {
warning ("Failed to associate portal window with parent window %s", parent_handle);
} else {
parent.set_parent_of (get_window ());
}
}
public Dialog (string app_id, string parent_window, string icon) {
Object (
app_id: app_id,
parent_window: parent_window,
image_icon: new ThemedIcon (icon),
buttons: Gtk.ButtonsType.NONE
);
}

construct {
set_keep_above (true);
skip_taskbar_hint = true;
resizable = false;
modal = true;

deny_button = add_button (_("Deny Access"), Gtk.ResponseType.CANCEL) as Gtk.Button;
choices = new List<Choice> ();
set_keep_above (true);

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;
grant_button.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION);

set_default (deny_button);

choices = new HashTable<unowned string, string> (str_hash, str_equal);
box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
custom_bin.add (box);
custom_bin.child = box;
box.show ();

response.connect_after (() => {
destroy ();
});
if (parent_window != "") {
realize.connect (() => {
try {
var parent = ExternalWindow.from_handle (parent_window);
parent.set_parent_of (get_window ());
} catch (Error e) {
warning ("Failed to associate portal window with parent %s: %s", parent_window, e.message);
}
});
}

destroy.connect (() => {
if (register_id != 0) {
connection.unregister_object (register_id);
register_id = 0;
show.connect (() => {
var window = get_window ();
if (window == null) {
return;
}

window.focus (Gdk.CURRENT_TIME);
});

response.connect_after (destroy);
}

[DBus (visible = false)]
public void add_choice (Variant choice) {
unowned string id, label, selected;
Variant options;

choice.get ("(&s&s@a(ss)&s)", out id, out label, out options, out selected);

if (options.n_children () > 0) {
var group_label = new Gtk.Label (label);
Gtk.RadioButton group = null;

group_label.get_style_context ().add_class ("dim-label");
box.add (group_label);

for (size_t i = 0; i < options.n_children (); ++i) {
unowned string option_id, option_label;

options.get_child (i, "(&s&s)", out option_id, out option_label);
var button = new Gtk.RadioButton.with_label_from_widget (group, option_label) {
active = selected == option_id
};

button.set_data<string> ("choice-id", id);
button.set_data<string> ("option-id", option_id);
button.toggled.connect (() => {
if (button.active) {
choices.set (
button.get_data<string> ("choice-id"),
button.get_data<string> ("option-id")
);
}
});

button.show ();
box.add (button);

if (group == null) {
group = button;
}
}
} else {
var button = new Gtk.CheckButton.with_label (label) {
active = bool.parse (selected)
};

button.set_data<string> ("choice-id", id);
button.toggled.connect (() => {
choices.set (
button.get_data<string> ("choice-id"),
button.active.to_string ()
);
});

button.show_all ();
box.add (button);
}
public void add_choice (Choice choice) {
choices.append (choice);
box.add (choice);
}

choices[id] = selected;
[DBus (visible = false)]
public unowned List<Choice> get_choices () {
return choices;
}

[DBus (name = "Close")]
Expand Down
72 changes: 48 additions & 24 deletions src/Access/Portal.vala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
*
*
* SPDX-FileCopyrightText: 2021 elementary, Inc. (https://elementary.io)
* SPDX-License-Identifier: LGPL-2.1-or-later
*/

[DBus (name = "org.freedesktop.impl.portal.Access")]
Expand All @@ -22,44 +22,67 @@ public class Access.Portal : Object {
out uint32 response,
out HashTable<string, Variant> results
) throws DBusError, IOError {
string icon = "dialog-information";

var dialog = new Dialog (
connection,
handle,
app_id,
parent_window,
title,
sub_title,
body
);

if ("modal" in options && options["modal"].is_of_type (VariantType.BOOLEAN)) {
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 (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 && options["deny_label"].is_of_type (VariantType.STRING)) {
}

if ("deny_label" in options) {
dialog.deny_label = options["deny_label"].get_string ();
} if ("grant_label" in options && options["grant_label"].is_of_type (VariantType.STRING)) {
}

if ("grant_label" in options) {
dialog.grant_label = options["grant_label"].get_string ();
} if ("icon" in options && options["icon"].is_of_type (VariantType.STRING)) {
// elementary HIG use non-symbolic icon, while portals ask for symbolic ones.
dialog.image_icon = new ThemedIcon (options["icon"].get_string ().replace ("-symbolic", ""));
}

if ("choices" in options && options["choices"].is_of_type (new VariantType ("a(ssa(ss)s)"))) {
var choices = options["choices"];
if ("choices" in options) {
var choices_iter = options["choices"].iterator ();
Variant choice_variant;

for (size_t i = 0; i < choices.n_children (); ++i) {
dialog.add_choice (choices.get_child_value (i));
while ((choice_variant = choices_iter.next_value ()) != null) {
dialog.add_choice (new Choice.from_variant (choice_variant));
}
}

try {
dialog.register_id = connection.register_object (handle, dialog);
} catch (Error e) {
critical (e.message);
}

var _results = new HashTable<string, Variant> (str_hash, str_equal);
uint _response = 2;

dialog.destroy.connect (() => {
if (dialog.register_id != 0) {
connection.unregister_object (dialog.register_id);
dialog.register_id = 0;
}
});

dialog.response.connect ((id) => {
switch ((Gtk.ResponseType) id) {
switch (id) {
case Gtk.ResponseType.OK:
VariantBuilder 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;
_results["choices"] = dialog.choices;
break;
case Gtk.ResponseType.CANCEL:
_response = 1;
Expand All @@ -74,6 +97,7 @@ public class Access.Portal : Object {

dialog.show_all ();
yield;

results = _results;
response = _response;
}
Expand Down
1 change: 1 addition & 0 deletions src/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ executable(
'ExternalWindow.vala',
'Access/Portal.vala',
'Access/Dialog.vala',
'Access/Choice.vala',
'AppChooser/Portal.vala',
'AppChooser/Dialog.vala',
'AppChooser/AppButton.vala',
Expand Down

0 comments on commit e74df0e

Please sign in to comment.