Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alongside Option #173

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Dialogs/DecryptDialog.vala
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ public class DecryptDialog: Gtk.Dialog {
unowned Distinst.Disks disks = options.borrow_disks ();
foreach (unowned Distinst.Partition partition in disks.get_encrypted_partitions ()) {
string path = Utils.string_from_utf8 (partition.get_device_path ());

bool is_unlocked = options.is_unlocked (path);

var lock_icon_name = is_unlocked ? "emblem-unlocked" : "dialog-password";
Expand Down
41 changes: 41 additions & 0 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
public class Installer.MainWindow : Gtk.Dialog {
private Gtk.Stack stack;

private AlongsideView alongside_view;
private DiskView disk_view;
private EncryptView encrypt_view;
private ErrorView error_view;
Expand All @@ -30,6 +31,7 @@ public class Installer.MainWindow : Gtk.Dialog {
private PartitioningView partitioning_view;
private ProgressView progress_view;
private RefreshView refresh_view;
private ResizeView resize_view;
private SuccessView success_view;
private TryInstallView try_install_view;
private bool check_ignored = false;
Expand Down Expand Up @@ -132,6 +134,45 @@ public class Installer.MainWindow : Gtk.Dialog {
try_install_view.custom_step.connect (load_partitioning_view);
try_install_view.next_step.connect (load_disk_view);
try_install_view.refresh_step.connect (load_refresh_view);
try_install_view.alongside_step.connect (load_alongside_view);
}

private void load_alongside_view () {
if (alongside_view == null) {
alongside_view = new AlongsideView ();
alongside_view.previous_view = try_install_view;
alongside_view.next_step.connect ((set_scale, os, free, total) => {
if (set_scale) {
load_resize_view (os, free, total);
} else {
load_encrypt_view ();
}
});

alongside_view.cancel.connect (() => {
stack.visible_child = try_install_view;
});
stack.add (alongside_view);
}

stack.visible_child = alongside_view;
alongside_view.update_options ();
}

private void load_resize_view (string? os, uint64 free, uint64 total) {
if (resize_view == null) {
resize_view = new ResizeView (minimum_disk_size);
resize_view.previous_view = alongside_view;
resize_view.next_step.connect (load_encrypt_view);
resize_view.cancel.connect (() => {
stack.visible_child = alongside_view;
});

stack.add (resize_view);
}

stack.visible_child = resize_view;
resize_view.update_options (os, free, total);
}

private void load_refresh_view () {
Expand Down
24 changes: 24 additions & 0 deletions src/Objects/InstallOptions.vala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public class InstallOptions : GLib.Object {

private Gee.ArrayList<string> unlocked_devices { get; set; default = new Gee.ArrayList<string> (); }

private unowned Distinst.Disk? install_device;
private string? install_device_path;

// The amount of free space that should be retained when shrinking (20 GiB).
public const uint64 SHRINK_OVERHEAD = 20 * 2 * 1024 * 1024;

Expand All @@ -40,6 +43,25 @@ public class InstallOptions : GLib.Object {
return _options_object;
}

public unowned Distinst.Disk? get_install_device () {
if (install_device == null) {
install_device = disks.get_disk_with_mount ("/cdrom");
}

return install_device;
}

public unowned string? get_install_device_path () {
if (install_device_path == null) {
unowned Distinst.Disk? install_device = get_install_device ();
if (install_device != null) {
install_device_path = Utils.string_from_utf8 (install_device.get_device_path ());
}
}

return install_device_path;
}

public void set_minimum_size (uint64 size) {
minimum_size = size;
}
Expand Down Expand Up @@ -118,6 +140,8 @@ public class InstallOptions : GLib.Object {
// Transder ownership of the disks to the caller.
public Distinst.Disks take_disks () {
disks_moved = true;
install_device = null;
install_device_path = null;
return (owned) disks;
}

Expand Down
210 changes: 210 additions & 0 deletions src/Views/AlongsideView.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/**
* This view is for selecting a location to install alongside an existing operationg system.
*
* Possible install options on this view are:
*
* - Shrinking the largest existing partition on a disk, if possible.
* - Installing to the largest unused region on a disk, if possible.
*/
public class AlongsideView: OptionsView {
public signal void next_step (bool use_scale, string? os, uint64 free, uint64 total);

// Whether to use the resize view for choosing a size or not.
public bool set_scale = false;
// The number of free sectors that the selected install option has.
public uint64 selected_free = 0;
// The number of total sectors that the option has.
public uint64 selected_total = 0;
// The OS that is installed to, or may have ownership of, the option.
public string? selected_os;

// Possible labels that the next button will have, depending on which option is selected.
private string NEXT_LABEL[5];

public AlongsideView () {
Object (
cancellable: true,
artwork: "disks",
title: _("Install Alongside Another OS")
);
}

construct {
NEXT_LABEL = new string[5] {
_("Install"),
_("Resize Partition"),
_("Resize OS"),
_("Install Alongside"),
_("Erase and Install"),
};

next_button.label = NEXT_LABEL[3];
next.connect (() => next_step (set_scale, selected_os, selected_free, selected_total));
show_all ();
}

// Clears existing options in the view, and creates new installation options.
public void update_options () {
base.clear_options ();

var options = InstallOptions.get_default ();

add_alongside_options ();

if (options.get_options ().has_erase_options ()) {
add_erase_options ();
}

base.options.show_all ();
base.select_first_option ();
}

private void add_alongside_options () {
var install_options = InstallOptions.get_default ();
unowned string? install_device = install_options.get_install_device_path ();

foreach (var option in install_options.get_options ().get_alongside_options ()) {
var device = Utils.string_from_utf8 (option.get_device ());

if (install_device != null && install_device == device) {
debug ("skipping %s because it is on the install device\n", device);
continue;
}

string? os = Utils.string_from_utf8 (option.get_os ());
os = os == "none" ? null : os;

var free = option.get_sectors_free ();
var total = option.get_sectors_total ();
var partition = option.get_partition ();
var partition_path = Utils.string_from_utf8 (option.get_path ());
string logo = Utils.get_distribution_logo_from_alongside (option);

string label;
string details;
if (partition == -1) {
label = _("Unused space on %s").printf (device);
details = _("%.1f GiB available").printf ((double) free / SECTORS_AS_GIB);
} else {
label = _("%s on %s").printf (os == null ? _("Partition") : os, device);
details = _("Shrink %s (%.1f GiB free)")
.printf (
partition_path,
(double) free / SECTORS_AS_GIB
);
}

base.add_option (logo, label, details, (button) => {
unowned string next_label;
if (partition == -1) {
next_label = NEXT_LABEL[0];
} else if (os == null) {
next_label = NEXT_LABEL[1];
} else {
next_label = NEXT_LABEL[2];
}

button.key_press_event.connect ((event) => handle_key_press (button, event));
button.notify["active"].connect (() => {
if (button.active) {
base.options.get_children ().foreach ((child) => {
if (child is Gtk.ToggleButton) {
((Gtk.ToggleButton)child).active = child == button;
}
});

install_options.selected_option = new Distinst.InstallOption () {
tag = Distinst.InstallOptionVariant.ALONGSIDE,
option = (void*) option,
encrypt_pass = null,
sectors = (partition == -1) ? 0 : free - 1
};

set_scale = partition != -1;
selected_os = os;
selected_free = free;
selected_total = total;
next_button.label = next_label;
next_button.sensitive = true;
} else {
next_button.label = NEXT_LABEL[3];
next_button.sensitive = false;
}
});
});
}
}

private void add_erase_options () {
var install_options = InstallOptions.get_default ();
unowned Distinst.InstallOptions options = install_options.get_updated_options ();
unowned string? install_device = install_options.get_install_device_path ();

foreach (unowned Distinst.EraseOption disk in options.get_erase_options ()) {
string device_path = Utils.string_from_utf8 (disk.get_device_path ());

if (install_device != null && install_device == device_path && !install_options.has_recovery ()) {
continue;
}

string logo = Utils.string_from_utf8 (disk.get_linux_icon ());
string label = Utils.string_from_utf8 (disk.get_model ());
string details = "Erase %s %.1f GiB".printf (
Utils.string_from_utf8 (disk.get_device_path ()),
(double) disk.get_sectors () / SECTORS_AS_GIB
);

base.add_option(logo, label, details, (button) => {
if (disk.meets_requirements ()) {
button.key_press_event.connect ((event) => handle_key_press (button, event));
button.notify["active"].connect (() => {
if (button.active) {
base.options.get_children ().foreach ((child) => {
if (child is Gtk.ToggleButton) {
((Gtk.ToggleButton)child).active = child == button;
}
});

if (install_options.has_recovery ()) {
var recovery = options.get_recovery_option ();

install_options.selected_option = new Distinst.InstallOption () {
tag = Distinst.InstallOptionVariant.RECOVERY,
option = (void*) recovery,
encrypt_pass = null
};
} else {
install_options.selected_option = new Distinst.InstallOption () {
tag = Distinst.InstallOptionVariant.ERASE,
option = (void*) disk,
encrypt_pass = null
};
}

set_scale = false;
next_button.label = NEXT_LABEL[4];
next_button.sensitive = true;
} else {
next_button.sensitive = false;
next_button.label = NEXT_LABEL[3];
}
});
} else {
button.sensitive = false;
}
});
}

base.sort_sensitive ();
}

private bool handle_key_press (Gtk.Button button, Gdk.EventKey event) {
if (event.keyval == Gdk.Key.Return) {
button.clicked ();
next_button.clicked ();
return true;
}

return false;
}
}
7 changes: 7 additions & 0 deletions src/Views/DiskView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,15 @@ public class Installer.DiskView : OptionsView {

var install_options = InstallOptions.get_default ();
unowned Distinst.InstallOptions options = install_options.get_updated_options ();
unowned string? install_device = install_options.get_install_device_path ();

foreach (unowned Distinst.EraseOption disk in options.get_erase_options ()) {
string device_path = Utils.string_from_utf8 (disk.get_device_path ());

if (install_device != null && install_device == device_path && !install_options.has_recovery ()) {
continue;
}

string logo = Utils.string_from_utf8 (disk.get_linux_icon ());
string label = Utils.string_from_utf8 (disk.get_model ());
string details = "%s %.1f GiB".printf (
Expand Down
Loading