From cad8820865f339a5c3ce05bea899bd5627ff8353 Mon Sep 17 00:00:00 2001 From: Clement Lefebvre Date: Sun, 29 May 2022 12:24:56 +0100 Subject: [PATCH] Revert "Remove trailing spaces" This reverts commit f04fb67babf3b302245b849a12f0b85920f6331f. I thought Tony was done updating his repository when committing this. I revert it for now as it makes merging difficult and it isn't urgent to fix. --- makefile | 10 +- src/Console/AppConsole.vala | 120 ++-- src/Core/AppExcludeEntry.vala | 42 +- src/Core/Main.vala | 732 +++++++++++------------ src/Core/Snapshot.vala | 142 ++--- src/Core/SnapshotRepo.vala | 222 +++---- src/Core/Subvolume.vala | 48 +- src/Gtk/AppGtk.vala | 14 +- src/Gtk/BackupBox.vala | 40 +- src/Gtk/BackupDeviceBox.vala | 134 ++--- src/Gtk/BackupFinishBox.vala | 10 +- src/Gtk/BackupWindow.vala | 74 +-- src/Gtk/BootOptionsBox.vala | 44 +- src/Gtk/BootOptionsWindow.vala | 20 +- src/Gtk/DeleteBox.vala | 24 +- src/Gtk/DeleteFinishBox.vala | 10 +- src/Gtk/DeleteWindow.vala | 90 +-- src/Gtk/EstimateBox.vala | 24 +- src/Gtk/ExcludeAppsBox.vala | 24 +- src/Gtk/ExcludeBox.vala | 110 ++-- src/Gtk/ExcludeListSummaryWindow.vala | 24 +- src/Gtk/ExcludeMessageWindow.vala | 10 +- src/Gtk/FinishBox.vala | 14 +- src/Gtk/MainWindow.vala | 196 +++--- src/Gtk/MiscBox.vala | 38 +- src/Gtk/RestoreBox.vala | 46 +- src/Gtk/RestoreDeviceBox.vala | 100 ++-- src/Gtk/RestoreExcludeBox.vala | 26 +- src/Gtk/RestoreFinishBox.vala | 14 +- src/Gtk/RestoreSummaryBox.vala | 14 +- src/Gtk/RestoreWindow.vala | 150 ++--- src/Gtk/RsyncLogBox.vala | 124 ++-- src/Gtk/RsyncLogWindow.vala | 8 +- src/Gtk/ScheduleBox.vala | 58 +- src/Gtk/SettingsWindow.vala | 38 +- src/Gtk/SetupWizardWindow.vala | 80 +-- src/Gtk/SnapshotBackendBox.vala | 34 +- src/Gtk/SnapshotListBox.vala | 116 ++-- src/Gtk/UsersBox.vala | 104 ++-- src/Utility/AppLock.vala | 10 +- src/Utility/AsyncTask.vala | 100 ++-- src/Utility/CronTab.vala | 40 +- src/Utility/CryptTabEntry.vala | 24 +- src/Utility/DeleteFileTask.vala | 36 +- src/Utility/Device.vala | 194 +++--- src/Utility/FileItem.vala | 34 +- src/Utility/FsTabEntry.vala | 68 +-- src/Utility/Gtk/AboutWindow.vala | 42 +- src/Utility/Gtk/CustomMessageDialog.vala | 22 +- src/Utility/Gtk/DonationWindow.vala | 44 +- src/Utility/Gtk/TerminalWindow.vala | 50 +- src/Utility/GtkHelper.vala | 90 +-- src/Utility/IconManager.vala | 64 +- src/Utility/LinuxDistro.vala | 8 +- src/Utility/MountEntry.vala | 20 +- src/Utility/OSDNotify.vala | 22 +- src/Utility/RsyncTask.vala | 96 +-- src/Utility/SystemUser.vala | 36 +- src/Utility/TeeJee.FileSystem.vala | 112 ++-- src/Utility/TeeJee.Json.vala | 6 +- src/Utility/TeeJee.Logging.vala | 8 +- src/Utility/TeeJee.Misc.vala | 28 +- src/Utility/TeeJee.Process.vala | 58 +- src/Utility/TeeJee.System.vala | 68 +-- src/Utility/TimeoutCounter.vala | 10 +- src/makefile | 12 +- src/timeshift-uninstall | 2 +- 67 files changed, 2216 insertions(+), 2216 deletions(-) diff --git a/makefile b/makefile index 2853ef4..9597f4b 100644 --- a/makefile +++ b/makefile @@ -3,13 +3,13 @@ all: app-gtk: cd src; make app-gtk - + app-console: cd src; make app-console manpage: cd src; make manpage - + dist-release: build-release @@ -17,18 +17,18 @@ dist-publish: build-update-repo-debian build-update-repo-redhat build-update-repo-archlinux - + dist-upload: build-upload dist-deb: build-deb amd64 - + clean: cd src; make clean install: cd src; make install - + uninstall: cd src; make uninstall diff --git a/src/Console/AppConsole.vala b/src/Console/AppConsole.vala index 9cd70f7..bd57fe1 100644 --- a/src/Console/AppConsole.vala +++ b/src/Console/AppConsole.vala @@ -52,11 +52,11 @@ public class AppConsole : GLib.Object { public int snapshot_list_start_index = 0; public static int main (string[] args) { - + set_locale(); LOG_TIMESTAMP = false; - + if (args.length > 1) { switch (args[1].down()) { case "--help": @@ -73,13 +73,13 @@ public class AppConsole : GLib.Object { LOG_ENABLE = false; init_tmp(AppShortName); LOG_ENABLE = true; - + check_if_admin(); App = new Main(args, false); parse_arguments(args); App.initialize(); - + var console = new AppConsole(); bool ok = console.start_application(); App.exit_app((ok) ? 0 : 1); @@ -88,7 +88,7 @@ public class AppConsole : GLib.Object { } private static void set_locale() { - + log_debug("setting locale..."); Intl.setlocale(GLib.LocaleCategory.MESSAGES, "timeshift"); Intl.textdomain(GETTEXT_PACKAGE); @@ -97,7 +97,7 @@ public class AppConsole : GLib.Object { } public static void check_if_admin(){ - + if (!user_is_admin()) { log_msg(_("Application needs admin access.")); log_msg(_("Please run the application as admin (using 'sudo' or 'su')")); @@ -111,7 +111,7 @@ public class AppConsole : GLib.Object { private static void parse_arguments(string[] args){ log_debug("AppConsole: parse_arguments()"); - + for (int k = 1; k < args.length; k++) // Oth arg is app path { switch (args[k].down()){ @@ -158,7 +158,7 @@ public class AppConsole : GLib.Object { case "--comment": case "--comments": App.cmd_comments = args[++k]; - break; + break; case "--skip-grub": App.cmd_skip_grub = true; @@ -245,7 +245,7 @@ public class AppConsole : GLib.Object { log_error("Run 'timeshift --help' to list all available options"); App.exit_app(1); break; - + default: LOG_TIMESTAMP = false; log_error("%s: %s".printf( @@ -274,7 +274,7 @@ public class AppConsole : GLib.Object { public bool start_application(){ log_debug("AppConsole: start_application()"); - + bool is_success = true; if (App.live_system()){ @@ -335,10 +335,10 @@ public class AppConsole : GLib.Object { } private static string help_message (){ - + string msg = "\n%s v%s by Tony George (%s)\n".printf( AppName, AppVersion, AppAuthorEmail); - + msg += "\n"; msg += "Syntax:\n"; msg += "\n"; @@ -445,7 +445,7 @@ public class AppConsole : GLib.Object { } private void list_devices(Gee.ArrayList device_list){ - + string[,] grid = new string[device_list.size+1,6]; bool[] right_align = { false, false, false, true, true, false}; @@ -523,7 +523,7 @@ public class AppConsole : GLib.Object { if (dev.type == "disk"){ grub_device_list.add(dev); } - else if (dev.type == "part"){ + else if (dev.type == "part"){ if (dev.has_linux_filesystem()){ grub_device_list.add(dev); } @@ -599,15 +599,15 @@ public class AppConsole : GLib.Object { select_snapshot_device(false); return App.create_snapshot(ondemand, null); } - + // restore - + private bool restore_snapshot(){ select_snapshot_device(true); select_snapshot_for_restore(); - + stdout.printf("\n\n"); log_msg(string.nfill(78, '*')); stdout.printf(_("To restore with default options, press the ENTER key for all prompts!") + "\n"); @@ -617,7 +617,7 @@ public class AppConsole : GLib.Object { stdin.read_line(); init_mounts(); - + if (!App.btrfs_mode){ map_devices(); @@ -647,13 +647,13 @@ public class AppConsole : GLib.Object { list.add(pi); } } - + if ((App.repo.device == null) || (prompt_if_empty && (App.repo.snapshots.size == 0))){ //prompt user for backup device log_msg(""); if (App.cmd_scripted){ - + if (App.repo.device == null){ if (App.backup_uuid.length == 0){ log_debug("device is null"); @@ -694,7 +694,7 @@ public class AppConsole : GLib.Object { } log_msg(""); - + if (dev == null){ log_error(_("Failed to get input from user in 3 attempts")); log_msg(_("Aborted.")); @@ -711,13 +711,13 @@ public class AppConsole : GLib.Object { private Snapshot? select_snapshot(){ Snapshot selected_snapshot = null; - + log_debug("AppConsole: select_snapshot()"); - + if (App.mirror_system){ return null; } - + if (App.cmd_snapshot.length > 0){ //check command line arguments @@ -758,7 +758,7 @@ public class AppConsole : GLib.Object { selected_snapshot = read_stdin_snapshot(); } log_msg(""); - + if (selected_snapshot == null){ log_error(_("Failed to get input from user in 3 attempts")); log_msg(_("Aborted.")); @@ -784,18 +784,18 @@ public class AppConsole : GLib.Object { App.exit_app(1); } } - + private void init_mounts(){ log_debug("AppConsole: init_mounts()"); - + App.init_mount_list(); // remove mount points which will remain on root fs for(int i = App.mount_list.size-1; i >= 0; i--){ - + var entry = App.mount_list[i]; - + if (entry.device == null){ App.mount_list.remove(entry); } @@ -805,15 +805,15 @@ public class AppConsole : GLib.Object { private void map_devices(){ log_debug("AppConsole: map_devices()"); - + if (App.cmd_target_device.length > 0){ //check command line arguments bool found = false; foreach(Device pi in App.partitions) { - + if (!pi.has_linux_filesystem()) { continue; } - + if ((pi.device == App.cmd_target_device)||((pi.uuid == App.cmd_target_device))){ App.dst_root = pi; found = true; @@ -840,7 +840,7 @@ public class AppConsole : GLib.Object { } for(int i = 0; i < App.mount_list.size; i++){ - + MountEntry mnt = App.mount_list[i]; Device dev = null; string default_device = ""; @@ -850,7 +850,7 @@ public class AppConsole : GLib.Object { // no need to ask user to map remaining devices if restoring same system if ((App.dst_root != null) && (App.sys_root != null) && (App.dst_root.uuid == App.sys_root.uuid)){ - + break; } @@ -878,14 +878,14 @@ public class AppConsole : GLib.Object { while (dev == null){ attempts++; if (attempts > 3) { break; } - + stdout.printf("" + _("[ENTER = Default (%s), r = Root device, a = Abort]").printf(default_device) + "\n\n"); - + stdout.printf( _("Enter device name or number") + ": "); - + stdout.flush(); dev = read_stdin_device_mounts(device_list, mnt); } @@ -901,26 +901,26 @@ public class AppConsole : GLib.Object { if (dev != null){ log_debug("selected: %s".printf(dev.uuid)); - + mnt.device = dev; log_msg(string.nfill(78, '*')); - + if ((mnt.mount_point != "/") && (App.dst_root != null) && (dev.device == App.dst_root.device)){ - + log_msg(_("'%s' will be on root device").printf(mnt.mount_point), true); } else{ log_msg(_("'%s' will be on '%s'").printf( mnt.mount_point, mnt.device.short_name_with_alias), true); - + //log_debug("UUID=%s".printf(dst_root.uuid)); } log_msg(string.nfill(78, '*')); } - + } } @@ -930,17 +930,17 @@ public class AppConsole : GLib.Object { bool grub_reinstall_default = App.reinstall_grub2; App.reinstall_grub2 = false; App.grub_device = ""; - + if (App.cmd_grub_device.length > 0){ log_debug("Grub device is specified as command argument"); - + //check command line arguments bool found = false; var device_list = list_grub_devices(false); - + foreach(Device dev in device_list) { - + if ((dev.device == App.cmd_grub_device) ||((dev.uuid.length > 0) && (dev.uuid == App.cmd_grub_device))){ @@ -969,7 +969,7 @@ public class AppConsole : GLib.Object { return; } } - + if (App.mirror_system){ App.reinstall_grub2 = true; } @@ -995,7 +995,7 @@ public class AppConsole : GLib.Object { } if ((App.reinstall_grub2) && (App.grub_device.length == 0)){ - + log_msg(""); log_msg(_("Select GRUB device") + ":\n"); var device_list = list_grub_devices(); @@ -1003,7 +1003,7 @@ public class AppConsole : GLib.Object { int attempts = 0; while (App.grub_device.length == 0){ - + attempts++; if (attempts > 3) { break; } @@ -1023,15 +1023,15 @@ public class AppConsole : GLib.Object { list.add(pi); } } - + Device dev = read_stdin_device(device_list, grub_device_default); if (dev != null) { App.grub_device = dev.device; } } - + log_msg(""); if (App.grub_device.length == 0){ - + log_error(_("Failed to get input from user in 3 attempts")); log_msg(_("Aborted.")); App.exit_app(0); @@ -1039,7 +1039,7 @@ public class AppConsole : GLib.Object { } if ((App.reinstall_grub2) && (App.grub_device.length > 0)){ - + log_msg(string.nfill(78, '*')); log_msg(_("GRUB Device") + ": %s".printf(App.grub_device)); log_msg(string.nfill(78, '*')); @@ -1052,7 +1052,7 @@ public class AppConsole : GLib.Object { } private void confirm_restore(){ - + if (App.cmd_confirm == false){ string msg_devices = ""; @@ -1079,9 +1079,9 @@ public class AppConsole : GLib.Object { } } } - + private Device? read_stdin_device(Gee.ArrayList device_list, string device_default){ - + var counter = new TimeoutCounter(); counter.exit_on_timeout(); string? line = stdin.read_line(); @@ -1272,7 +1272,7 @@ public class AppConsole : GLib.Object { private bool read_stdin_restore_confirm(){ var counter = new TimeoutCounter(); counter.exit_on_timeout(); - + string? line = stdin.read_line(); counter.stop(); @@ -1317,11 +1317,11 @@ public class AppConsole : GLib.Object { } public bool delete_all_snapshots(){ - + select_snapshot_device(true); - + //return App.repo.remove_all(); - + foreach(var snap in App.repo.snapshots){ snap.remove(true); } diff --git a/src/Core/AppExcludeEntry.vala b/src/Core/AppExcludeEntry.vala index 954112f..769784a 100644 --- a/src/Core/AppExcludeEntry.vala +++ b/src/Core/AppExcludeEntry.vala @@ -30,7 +30,7 @@ using TeeJee.System; using TeeJee.Misc; public class AppExcludeEntry : GLib.Object{ - + public string name = ""; public bool is_include = false; public bool is_file = false; @@ -42,7 +42,7 @@ public class AppExcludeEntry : GLib.Object{ public static Gee.HashMap app_map; public AppExcludeEntry(string _name, bool _is_include = false){ - + name = _name; is_include = _is_include; @@ -51,7 +51,7 @@ public class AppExcludeEntry : GLib.Object{ } public string tooltip_text(){ - + string txt = ""; foreach(var item in items){ txt += "%s\n".printf(item); @@ -60,14 +60,14 @@ public class AppExcludeEntry : GLib.Object{ txt = txt[0:txt.length - 1]; } return txt; - } - + } + // static - + public static void clear(){ log_debug("AppExcludeEntry: clear()"); - + if (app_map == null){ app_map = new Gee.HashMap(); } @@ -80,14 +80,14 @@ public class AppExcludeEntry : GLib.Object{ log_debug("AppExcludeEntry: add_app_exclude_entries_from_home()"); log_debug("path=%s".printf(home)); - + try { File f_home = File.new_for_path (home); if (!f_home.query_exists()){ return; } - + FileEnumerator enumerator = f_home.enumerate_children ("standard::*", 0); FileInfo file; while ((file = enumerator.next_file ()) != null) { @@ -97,7 +97,7 @@ public class AppExcludeEntry : GLib.Object{ if (name.has_suffix(".log")){ continue; } if (name.has_suffix(".old")){ continue; } if (name.has_suffix("~")){ continue; } - + add_app_exclude_entries_from_path(item); } } @@ -105,19 +105,19 @@ public class AppExcludeEntry : GLib.Object{ log_error (e.message); } } - + public static void add_app_exclude_entries_from_path(string user_home){ log_debug("AppExcludeEntry: add_app_exclude_entries_from_path()"); log_debug("path=%s".printf(user_home)); - + try { File f_home = File.new_for_path (user_home); if (!f_home.query_exists()){ return; } - + FileEnumerator enumerator = f_home.enumerate_children ("standard::*", 0); FileInfo file; while ((file = enumerator.next_file ()) != null) { @@ -136,7 +136,7 @@ public class AppExcludeEntry : GLib.Object{ if (name.has_suffix(".log")){ continue; } if (name.has_suffix(".old")){ continue; } if (name.has_suffix("~")){ continue; } - + var relpath = "~/%s".printf(name); add_item(relpath, !dir_exists(item), false); } @@ -151,7 +151,7 @@ public class AppExcludeEntry : GLib.Object{ if (name.has_suffix(".log")){ continue; } if (name.has_suffix(".old")){ continue; } if (name.has_suffix("~")){ continue; } - + var relpath = "~/.config/%s".printf(name); add_item(relpath, !dir_exists(item), false); } @@ -169,7 +169,7 @@ public class AppExcludeEntry : GLib.Object{ if (name.has_suffix("~")){ continue; } if (name == "applications"){ continue; } if (name == "Trash"){ continue; } - + var relpath = "~/.local/share/%s".printf(name); add_item(relpath, !dir_exists(item), false); } @@ -187,7 +187,7 @@ public class AppExcludeEntry : GLib.Object{ } var name = file_basename(item_path); - + if (name.has_suffix(".ini")){ name = name[0:name.length - ".ini".length]; } @@ -275,7 +275,7 @@ public class AppExcludeEntry : GLib.Object{ if (app_map == null){ app_map = new Gee.HashMap(); } - + foreach(var selected_name in selected_app_names){ if (app_map.has_key(selected_name)){ app_map[selected_name].enabled = true; @@ -284,7 +284,7 @@ public class AppExcludeEntry : GLib.Object{ app_map[selected_name].enabled = false; } } - + var list = new Gee.ArrayList(); foreach(var key in app_map.keys){ list.add(app_map[key]); @@ -294,11 +294,11 @@ public class AppExcludeEntry : GLib.Object{ GLib.CompareDataFunc entry_compare = (a, b) => { return strcmp(a.name.down(),b.name.down()); }; - + list.sort((owned) entry_compare); log_debug("apps: %d".printf(list.size)); - + return list; } } diff --git a/src/Core/Main.vala b/src/Core/Main.vala index 3fc6bff..b023d4c 100644 --- a/src/Core/Main.vala +++ b/src/Core/Main.vala @@ -37,7 +37,7 @@ using TeeJee.Misc; public bool GTK_INITIALIZED = false; public class Main : GLib.Object{ - + public string app_path = ""; public string share_folder = ""; public string rsnapshot_conf_path = ""; @@ -45,16 +45,16 @@ public class Main : GLib.Object{ public string app_conf_path_old = ""; public string app_conf_path_default = ""; public bool first_run = false; - + public string backup_uuid = ""; public string backup_parent_uuid = ""; public bool btrfs_mode = true; public bool include_btrfs_home_for_backup = false; public bool include_btrfs_home_for_restore = false; - + public bool stop_cron_emails = true; - + public Gee.ArrayList partitions; public Gee.ArrayList exclude_list_user; @@ -65,8 +65,8 @@ public class Main : GLib.Object{ public Gee.ArrayList exclude_list_apps; public Gee.ArrayList mount_list; public Gee.ArrayList exclude_app_names; - - public SnapshotRepo repo; + + public SnapshotRepo repo; //temp //private Gee.ArrayList grub_device_list; @@ -102,10 +102,10 @@ public class Main : GLib.Object{ //global vars for controlling threads public bool thr_success = false; - + public bool thread_estimate_running = false; public bool thread_estimate_success = false; - + public bool thread_restore_running = false; public bool thread_restore_success = false; @@ -114,7 +114,7 @@ public class Main : GLib.Object{ public bool thread_subvol_info_running = false; public bool thread_subvol_info_success = false; - + public int thr_retval = -1; public string thr_arg1 = ""; public bool thr_timeout_active = false; @@ -122,13 +122,13 @@ public class Main : GLib.Object{ public int startup_delay_interval_mins = 10; public int retain_snapshots_max_days = 200; - + public int64 snapshot_location_free_space = 0; public const uint64 MIN_FREE_SPACE = 1 * GB; public static uint64 first_snapshot_size = 0; public static int64 first_snapshot_count = 0; - + public string log_dir = ""; public string log_file = ""; public AppLock app_lock; @@ -137,7 +137,7 @@ public class Main : GLib.Object{ public const string date_format_default = "%Y-%m-%d %H:%M:%S"; public Gee.ArrayList delete_list; - + public Snapshot snapshot_to_delete; public Snapshot snapshot_to_restore; //public Device restore_target; @@ -158,11 +158,11 @@ public class Main : GLib.Object{ public string cmd_comments = ""; public string cmd_tags = ""; public bool? cmd_btrfs_mode = null; - + public string progress_text = ""; public Gtk.Window? parent_window = null; - + public RsyncTask task; public DeleteFileTask delete_file_task; @@ -177,7 +177,7 @@ public class Main : GLib.Object{ public Main(string[] args, bool gui_mode){ parse_some_arguments(args); - + if (gui_mode){ app_mode = ""; parent_window = new Gtk.Window(); // dummy @@ -192,12 +192,12 @@ public class Main : GLib.Object{ } check_and_remove_timeshift_btrfs(); - + // init log ------------------ try { string suffix = gui_mode ? "gui" : app_mode; - + DateTime now = new DateTime.now_local(); log_dir = "/var/log/timeshift"; log_file = path_combine(log_dir, @@ -221,9 +221,9 @@ public class Main : GLib.Object{ catch (Error e) { log_error (e.message); } - + // get Linux distribution info ----------------------- - + this.current_distro = LinuxDistro.get_dist_info("/"); if (LOG_DEBUG || gui_mode){ @@ -245,7 +245,7 @@ public class Main : GLib.Object{ // check and create lock ---------------------------- app_lock = new AppLock(); - + if (!app_lock.create("timeshift", app_mode)){ if (gui_mode){ string msg = ""; @@ -275,7 +275,7 @@ public class Main : GLib.Object{ this.app_conf_path_old = "/etc/timeshift.json"; this.app_conf_path_default = "/etc/timeshift/default.json"; //sys_root and sys_home will be initalized by update_partition_list() - + // check if running locally ------------------------ string local_exec = args[0]; @@ -313,7 +313,7 @@ public class Main : GLib.Object{ delete_file_task = new DeleteFileTask(); update_partitions(); - + detect_system_devices(); detect_encrypted_dirs(); @@ -323,21 +323,21 @@ public class Main : GLib.Object{ load_app_config(); IconManager.init(args, AppShortName); - + log_debug("Main(): ok"); } public void initialize(){ - + initialize_repo(); } public bool check_dependencies(out string msg){ - + msg = ""; log_debug("Main: check_dependencies()"); - + string[] dependencies = { "rsync","/sbin/blkid","df","mount","umount","fuser","crontab","cp","rm","touch","ln","sync","which"}; //"shutdown","chroot", string path; @@ -360,14 +360,14 @@ public class Main : GLib.Object{ } public void check_and_remove_timeshift_btrfs(){ - + if (cmd_exists("timeshift-btrfs")){ string std_out, std_err; exec_sync("timeshift-btrfs-uninstall", out std_out, out std_err); log_msg(_("** Uninstalled Timeshift BTRFS **")); } } - + public bool check_btrfs_layout_system(Gtk.Window? win = null){ log_debug("check_btrfs_layout_system()"); @@ -382,7 +382,7 @@ public class Main : GLib.Object{ msg += _("Only ubuntu-type layouts with @ and @home subvolumes are currently supported.") + "\n\n"; msg += _("Application will exit.") + "\n\n"; string title = _("Not Supported"); - + if (app_mode == ""){ gtk_set_busy(false, win); gtk_messagebox(title, msg, win, true); @@ -396,15 +396,15 @@ public class Main : GLib.Object{ } public bool check_btrfs_layout(Device? dev_root, Device? dev_home, bool unlock){ - + bool supported = true; // keep true for non-btrfs systems if ((dev_root != null) && (dev_root.fstype == "btrfs")){ - + if ((dev_home != null) && (dev_home.fstype == "btrfs")){ if (dev_home != dev_root){ - + supported = supported && check_btrfs_volume(dev_root, "@", unlock); if (include_btrfs_home_for_backup){ @@ -426,7 +426,7 @@ public class Main : GLib.Object{ } private void parse_some_arguments(string[] args){ - + for (int k = 1; k < args.length; k++) // Oth arg is app path { switch (args[k].down()){ @@ -444,7 +444,7 @@ public class Main : GLib.Object{ btrfs_mode = false; cmd_btrfs_mode = btrfs_mode; break; - + case "--check": app_mode = "backup"; break; @@ -482,23 +482,23 @@ public class Main : GLib.Object{ } private void detect_encrypted_dirs(){ - + current_system_users = SystemUser.read_users_from_file("/etc/passwd","",""); string txt = ""; users_with_encrypted_home = ""; encrypted_home_dirs = ""; encrypted_private_dirs = ""; - + foreach(var user in current_system_users.values){ - + if (user.is_system) { continue; } - + if (txt.length > 0) { txt += " "; } txt += "%s".printf(user.name); if (user.has_encrypted_home){ - + users_with_encrypted_home += " %s".printf(user.name); encrypted_home_dirs += "%s\n".printf(user.home_path); @@ -512,26 +512,26 @@ public class Main : GLib.Object{ } } users_with_encrypted_home = users_with_encrypted_home.strip(); - + log_debug("Users: %s".printf(txt)); log_debug("Encrypted home users: %s".printf(users_with_encrypted_home)); log_debug("Encrypted home dirs:\n%s".printf(encrypted_home_dirs)); log_debug("Encrypted private dirs:\n%s".printf(encrypted_private_dirs)); } - + // exclude lists - + public void add_default_exclude_entries(){ log_debug("Main: add_default_exclude_entries()"); - + exclude_list_user = new Gee.ArrayList(); exclude_list_default = new Gee.ArrayList(); exclude_list_default_extra = new Gee.ArrayList(); exclude_list_home = new Gee.ArrayList(); exclude_list_restore = new Gee.ArrayList(); exclude_list_apps = new Gee.ArrayList(); - + partitions = new Gee.ArrayList(); // default exclude entries ------------------- @@ -631,7 +631,7 @@ public class Main : GLib.Object{ exclude_list_default_extra.add("/var/cache/xbps/*"); exclude_list_default_extra.add("/var/cache/zypp/*"); exclude_list_default_extra.add("/var/cache/edb/*"); - + // default home ---------------- //exclude_list_home.add("+ /root/.**"); @@ -657,9 +657,9 @@ public class Main : GLib.Object{ public void add_app_exclude_entries(){ log_debug("Main: add_app_exclude_entries()"); - + AppExcludeEntry.clear(); - + if (snapshot_to_restore != null){ add_app_exclude_entries_for_prefix(path_combine(snapshot_to_restore.path, "localhost")); } @@ -674,7 +674,7 @@ public class Main : GLib.Object{ } private void add_app_exclude_entries_for_prefix(string path_prefix){ - + string path = ""; path = path_combine(path_prefix, "root"); @@ -683,16 +683,16 @@ public class Main : GLib.Object{ path = path_combine(path_prefix, "home"); AppExcludeEntry.add_app_exclude_entries_from_home(path); } - + public Gee.ArrayList create_exclude_list_for_backup(){ log_debug("Main: create_exclude_list_for_backup()"); - + var list = new Gee.ArrayList(); // add default entries --------------------------- - + foreach(string path in exclude_list_default){ if (!list.contains(path)){ list.add(path); @@ -700,7 +700,7 @@ public class Main : GLib.Object{ } // add default extra entries --------------------------- - + foreach(string path in exclude_list_default_extra){ if (!list.contains(path)){ list.add(path); @@ -711,22 +711,22 @@ public class Main : GLib.Object{ // decrypted contents should never be backed-up or restored // this overrides all other user entries in exclude_list_user // ------------------------------------------------------- - + foreach(var user in current_system_users.values){ - + if (user.is_system){ continue; } - + if (user.has_encrypted_home){ - + // exclude decrypted contents in user's home ($HOME) string path = "%s/**".printf(user.home_path); list.add(path); } - + if (user.has_encrypted_private_dirs){ foreach(string enc_path in user.encrypted_private_dirs){ - + // exclude decrypted contents in private dirs ($HOME/Private) string path = "%s/**".printf(enc_path); list.add(path); @@ -748,7 +748,7 @@ public class Main : GLib.Object{ inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name); exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name); } - + bool include_hidden = exclude_list_user.contains(inc_hidden_pattern); bool include_all = exclude_list_user.contains(inc_pattern); bool exclude_all = !include_hidden && !include_all; @@ -767,7 +767,7 @@ public class Main : GLib.Object{ } // add user entries from current settings ---------- - + foreach(string path in exclude_list_user){ if (!list.contains(path)){ list.add(path); @@ -775,7 +775,7 @@ public class Main : GLib.Object{ } // add common entries for excluding home folders for all users -------- - + foreach(string path in exclude_list_home){ if (!list.contains(path)){ list.add(path); @@ -788,16 +788,16 @@ public class Main : GLib.Object{ } log_debug("Main: create_exclude_list_for_backup(): exit"); - + return list; } public Gee.ArrayList create_exclude_list_for_restore(){ log_debug("Main: create_exclude_list_for_restore()"); - + exclude_list_restore.clear(); - + //add default entries foreach(string path in exclude_list_default){ if (!exclude_list_restore.contains(path)){ @@ -830,7 +830,7 @@ public class Main : GLib.Object{ // skip include filters for restore if (path.strip().has_prefix("+")){ continue; } - + if (!exclude_list_restore.contains(path) && !exclude_list_home.contains(path)){ exclude_list_restore.add(path); } @@ -861,7 +861,7 @@ public class Main : GLib.Object{ } log_debug("Main: create_exclude_list_for_restore(): exit"); - + return exclude_list_restore; } @@ -869,16 +869,16 @@ public class Main : GLib.Object{ public bool save_exclude_list_for_backup(string output_path){ log_debug("Main: save_exclude_list_for_backup()"); - + var list = create_exclude_list_for_backup(); - + var txt = ""; foreach(var pattern in list){ if (pattern.strip().length > 0){ txt += "%s\n".printf(pattern); } } - + string list_file = path_combine(output_path, "exclude.list"); return file_write(list_file, txt); } @@ -886,11 +886,11 @@ public class Main : GLib.Object{ public bool save_exclude_list_for_restore(string output_path){ log_debug("Main: save_exclude_list_for_restore()"); - + var list = create_exclude_list_for_restore(); log_debug("Exclude list -------------"); - + var txt = ""; foreach(var pattern in list){ if (pattern.strip().length > 0){ @@ -898,14 +898,14 @@ public class Main : GLib.Object{ log_debug(pattern); } } - + return file_write(restore_exclude_file, txt); } public void save_exclude_list_selections(){ log_debug("Main: save_exclude_list_selections()"); - + // add new selected items foreach(var entry in exclude_list_apps){ if (entry.enabled && !exclude_app_names.contains(entry.name)){ @@ -928,7 +928,7 @@ public class Main : GLib.Object{ } //properties - + public bool scheduled{ get{ return !live_system() @@ -947,18 +947,18 @@ public class Main : GLib.Object{ public bool create_snapshot (bool is_ondemand, Gtk.Window? parent_win){ log_debug("Main: create_snapshot()"); - + bool status = true; bool update_symlinks = false; string sys_uuid = (sys_root == null) ? "" : sys_root.uuid; - + try { if (btrfs_mode && (check_btrfs_layout_system() == false)){ return false; } - + // create a timestamp DateTime now = new DateTime.now_local(); @@ -967,7 +967,7 @@ public class Main : GLib.Object{ log_error(repo.status_message); log_error(repo.status_details + "\n"); - + // remove invalid snapshots if (app_mode.length != 0){ repo.auto_remove(); @@ -991,7 +991,7 @@ public class Main : GLib.Object{ // ondemand if (is_ondemand){ - bool ok = create_snapshot_for_tag ("ondemand",now); + bool ok = create_snapshot_for_tag ("ondemand",now); if(!ok){ return false; } @@ -1168,11 +1168,11 @@ public class Main : GLib.Object{ log_msg(_("Scheduled snapshots are disabled") + " - " + _("Nothing to do!")); cron_job_update(); } - + log_msg(string.nfill(78, '-')); repo.load_snapshots(); // reload list for new snapshot - + if (app_mode.length != 0){ repo.auto_remove(); repo.load_snapshots(); @@ -1181,7 +1181,7 @@ public class Main : GLib.Object{ if (update_symlinks){ repo.create_symlinks(); } - + //log_msg("OK"); } catch(Error e){ @@ -1195,11 +1195,11 @@ public class Main : GLib.Object{ private bool create_snapshot_for_tag(string tag, DateTime dt_created){ log_debug("Main: backup_and_rotate()"); - + // save start time var dt_begin = new DateTime.now_local(); bool status = true; - + try{ // get system boot time DateTime now = new DateTime.now_local(); @@ -1235,10 +1235,10 @@ public class Main : GLib.Object{ } if (backup_to_rotate != null){ - + // tag the backup backup_to_rotate.add_tag(tag); - + var message = _("Tagged snapshot") + " '%s': %s".printf(backup_to_rotate.name, tag); log_msg(message); @@ -1251,7 +1251,7 @@ public class Main : GLib.Object{ log_error(repo.status_details); exit_app(); } - + // create new snapshot ----------------------- Snapshot new_snapshot = null; @@ -1261,13 +1261,13 @@ public class Main : GLib.Object{ else{ new_snapshot = create_snapshot_with_rsync(tag, dt_created); } - + // finish ------------------------------ - + var dt_end = new DateTime.now_local(); TimeSpan elapsed = dt_end.difference(dt_begin); long seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND); - + var message = ""; if (new_snapshot != null){ message = "%s %s (%lds)".printf((btrfs_mode ? "BTRFS" : "RSYNC"), _("Snapshot saved successfully"), seconds); @@ -1300,11 +1300,11 @@ public class Main : GLib.Object{ log_msg(_("Estimating system size...")); estimate_system_size(); } - + log_msg(_("Creating new snapshot...") + "(RSYNC)"); log_msg(_("Saving to device") + ": %s".printf(repo.device.device) + ", " + _("mounted at path") + ": %s".printf(repo.mount_path)); - + // take new backup --------------------------------- if (repo.mount_path.length == 0){ @@ -1319,7 +1319,7 @@ public class Main : GLib.Object{ dir_create(snapshot_path); string localhost_path = path_combine(snapshot_path, "localhost"); dir_create(localhost_path); - + string sys_uuid = (sys_root == null) ? "" : sys_root.uuid; Snapshot snapshot_to_link = null; @@ -1327,16 +1327,16 @@ public class Main : GLib.Object{ // check if a snapshot was restored recently and use it for linking --------- try{ - + string ctl_path = path_combine(snapshot_dir, ".sync-restore"); var f = File.new_for_path(ctl_path); - + if (f.query_exists()){ // read snapshot name from file string snap_path = file_read(ctl_path); string snap_name = file_basename(snap_path); - + // find the snapshot that was restored foreach(var bak in repo.snapshots){ if ((bak.name == snap_name) && (bak.sys_uuid == sys_uuid)){ @@ -1369,16 +1369,16 @@ public class Main : GLib.Object{ // save exclude list ---------------- bool ok = save_exclude_list_for_backup(snapshot_path); - + string exclude_from_file = path_combine(snapshot_path, "exclude.list"); if (!ok){ log_error(_("Failed to save exclude list")); return null; } - + // rsync file system ------------------- - + progress_text = _("Synching files with rsync..."); log_msg(progress_text); @@ -1399,7 +1399,7 @@ public class Main : GLib.Object{ task.delete_extra = true; task.delete_excluded = true; task.delete_after = false; - + if (app_mode.length > 0){ // console mode task.io_nice = true; @@ -1420,7 +1420,7 @@ public class Main : GLib.Object{ stdout.printf("\r"); stdout.flush(); - + if (task.total_size == 0){ log_error(_("rsync returned an error")); log_error(_("Failed to create new snapshot")); @@ -1428,7 +1428,7 @@ public class Main : GLib.Object{ } string initial_tags = (tag == "ondemand") ? "" : tag; - + // write control file // this step is redundant - just in case if app crashes while parsing log file in next step //Snapshot.write_control_file( @@ -1473,24 +1473,24 @@ public class Main : GLib.Object{ string snapshot_name = time_stamp; string sys_uuid = (sys_root == null) ? "" : sys_root.uuid; string snapshot_path = ""; - + // create subvolume snapshots var subvol_names = new string[] { "@" }; - + if (include_btrfs_home_for_backup){ - + subvol_names = new string[] { "@","@home" }; } - + foreach(var subvol_name in subvol_names){ snapshot_path = path_combine(repo.mount_paths[subvol_name], "timeshift-btrfs/snapshots/%s".printf(snapshot_name)); - + dir_create(snapshot_path, true); - + string src_path = path_combine(repo.mount_paths[subvol_name], subvol_name); - + string dst_path = path_combine(snapshot_path, subvol_name); // Dirty hack to fix the nested subvilumes issue (cause of issue is unknown) @@ -1500,17 +1500,17 @@ public class Main : GLib.Object{ else if (dst_path.has_suffix("/@home/@home")){ dst_path = dst_path.replace("/@home/@home", "/@home"); } - + string cmd = "btrfs subvolume snapshot '%s' '%s' \n".printf(src_path, dst_path); - + if (LOG_COMMANDS) { log_debug(cmd); } string std_out, std_err; - + int ret_val = exec_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ - + log_error (std_err); log_error(_("btrfs returned an error") + ": %d".printf(ret_val)); log_error(_("Failed to create subvolume snapshot") + ": %s".printf(subvol_name)); @@ -1526,7 +1526,7 @@ public class Main : GLib.Object{ snapshot_path = path_combine(repo.mount_paths["@"], "timeshift-btrfs/snapshots/%s".printf(snapshot_name)); string initial_tags = (tag == "ondemand") ? "" : tag; - + // write control file var snapshot = Snapshot.write_control_file( snapshot_path, dt_created, sys_uuid, current_distro.full_name(), @@ -1539,14 +1539,14 @@ public class Main : GLib.Object{ snapshot.update_control_file(); // save subvolume info set_tags(snapshot); // set_tags() will update the control file - + return snapshot; } private void set_tags(Snapshot snapshot){ // add tags passed on commandline for both --check and --create - + foreach(string tag in cmd_tags.split(",")){ switch(tag.strip().up()){ case "B": @@ -1568,7 +1568,7 @@ public class Main : GLib.Object{ } // add tag as ondemand if no other tag is specified - + if (snapshot.tags.size == 0){ snapshot.add_tag("ondemand"); } @@ -1591,14 +1591,14 @@ public class Main : GLib.Object{ } } } - + // gui delete public void delete_begin(){ log_debug("Main: delete_begin()"); progress_text = _("Preparing..."); - + try { thread_delete_running = true; thread_delete_success = false; @@ -1626,7 +1626,7 @@ public class Main : GLib.Object{ foreach(var bak in delete_list){ bak.mark_for_deletion(); } - + while (delete_list.size > 0){ var bak = delete_list[0]; @@ -1642,7 +1642,7 @@ public class Main : GLib.Object{ delete_file_task = bak.delete_file_task; delete_file_task.prg_count_total = (int64) Main.first_snapshot_count; - + status = bak.remove(true); // wait till complete if (delete_file_task.status != AppStatus.CANCELLED){ @@ -1657,7 +1657,7 @@ public class Main : GLib.Object{ thread_delete_running = false; thread_delete_success = status; } - + // restore - properties public Device? dst_root{ @@ -1735,12 +1735,12 @@ public class Main : GLib.Object{ } } } - + public bool restore_current_system{ get { if ((sys_root != null) && ((dst_root.device == sys_root.device) || (dst_root.uuid == sys_root.uuid))){ - + return true; } else{ @@ -1761,7 +1761,7 @@ public class Main : GLib.Object{ } } } - + public string restore_target_path{ owned get { if (restore_current_system){ @@ -1786,16 +1786,16 @@ public class Main : GLib.Object{ } // restore - + public void init_mount_list(){ log_debug("Main: init_mount_list()"); - + mount_list.clear(); Gee.ArrayList fstab_list = null; Gee.ArrayList crypttab_list = null; - + if (mirror_system){ string fstab_path = "/etc/fstab"; fstab_list = FsTabEntry.read_file(fstab_path); @@ -1811,21 +1811,21 @@ public class Main : GLib.Object{ bool boot_found = false; bool home_found = false; dst_root = null; - + foreach(var fs_entry in fstab_list){ // skip mounting for non-system devices ---------- - + if (!fs_entry.is_for_system_directory()){ continue; } // skip mounting excluded devices ----------------------- - + string p1 = "%s/*".printf(fs_entry.mount_point); string p2 = "%s/**".printf(fs_entry.mount_point); string p3 = "%s/***".printf(fs_entry.mount_point); - + if (exclude_list_default.contains(p1) || exclude_list_user.contains(p1)){ continue; } @@ -1837,7 +1837,7 @@ public class Main : GLib.Object{ } // find device by name or uuid -------------------------- - + Device dev_fstab = null; if (fs_entry.device_uuid.length > 0){ dev_fstab = Device.get_device_by_uuid(fs_entry.device_uuid); @@ -1852,30 +1852,30 @@ public class Main : GLib.Object{ Check if the device mentioned in fstab entry is a mapped device. If it is, then try finding the parent device which may be available on the current system. Prompt user to unlock it if found. - + Note: Mapped name may be different on running system, or it may be same. Since it is not reliable, we will try to identify the parent intead of the mapped device. */ - + if (fs_entry.device_string.has_prefix("/dev/mapper/")){ - + string mapped_name = fs_entry.device_string.replace("/dev/mapper/",""); - + foreach(var crypt_entry in crypttab_list){ - + if (crypt_entry.mapped_name == mapped_name){ // we found the entry for the mapped device fs_entry.device_string = crypt_entry.device_string; if (fs_entry.device_uuid.length > 0){ - + // we have the parent's uuid. get the luks device and prompt user to unlock it. var dev_luks = Device.get_device_by_uuid(fs_entry.device_uuid); - + if (dev_luks != null){ - + string msg_out, msg_err; var dev_unlocked = Device.luks_unlock( dev_luks, "", "", parent_window, out msg_out, out msg_err); @@ -1900,12 +1900,12 @@ public class Main : GLib.Object{ } if (dev_fstab != null){ - + log_debug("added: dev: %s, path: %s, options: %s".printf( dev_fstab.device, fs_entry.mount_point, fs_entry.options)); - + mount_list.add(new MountEntry(dev_fstab, fs_entry.mount_point, fs_entry.options)); - + if (fs_entry.mount_point == "/"){ dst_root = dev_fstab; } @@ -1949,12 +1949,12 @@ public class Main : GLib.Object{ All other mounts like /home will be defaulted to target device (to prevent the "cloned" system from using the original device) */ - + if (mirror_system){ dst_root = null; foreach (var entry in mount_list){ // user should select another device - entry.device = null; + entry.device = null; } } @@ -1973,7 +1973,7 @@ public class Main : GLib.Object{ }); init_boot_options(); // boot options depend on the mount list - + log_debug("Main: init_mount_list(): exit"); } @@ -2009,26 +2009,26 @@ public class Main : GLib.Object{ } } } - + public bool restore_snapshot(Gtk.Window? parent_win){ log_debug("Main: restore_snapshot()"); - + parent_window = parent_win; // remove mount points which will remain on root fs - + for(int i = mount_list.size-1; i >= 0; i--){ var entry = mount_list[i]; if (entry.device == null){ mount_list.remove(entry); } } - + // check if we have all required inputs and abort on error - + if (!mirror_system){ - + if (repo.device == null){ log_error(_("Backup device not specified!")); return false; @@ -2038,7 +2038,7 @@ public class Main : GLib.Object{ log_msg(_("Backup Device") + ": %s".printf(repo.device.device)); log_msg(string.nfill(78, '*')); } - + if (snapshot_to_restore == null){ log_error(_("Snapshot to restore not specified!")); return false; @@ -2054,7 +2054,7 @@ public class Main : GLib.Object{ log_msg(string.nfill(78, '*')); } } - + // final check - check if target root device is mounted if (btrfs_mode){ @@ -2084,7 +2084,7 @@ public class Main : GLib.Object{ try { thread_restore_running = true; thr_success = false; - + if (btrfs_mode){ Thread.create (restore_execute_btrfs, true); } @@ -2108,19 +2108,19 @@ public class Main : GLib.Object{ } log_debug("Main: restore_snapshot(): exit"); - + return thr_success; } public void get_restore_messages(bool formatted, out string msg_devices, out string msg_reboot, out string msg_disclaimer){ - + string msg = ""; log_debug("Main: get_restore_messages()"); // msg_devices ----------------------------------------- - + if (!formatted){ msg += "\n%s\n%s\n%s\n".printf( string.nfill(70,'='), @@ -2128,25 +2128,25 @@ public class Main : GLib.Object{ string.nfill(70,'=') ); } - + msg += _("Data will be modified on following devices:") + "\n\n"; int max_mount = _("Mount").length; int max_dev = _("Device").length; foreach(var entry in mount_list){ - + if (entry.device == null){ continue; } if (btrfs_mode){ - + if (entry.subvolume_name().length == 0){ continue; } - + if (!App.snapshot_to_restore.subvolumes.has_key(entry.subvolume_name())){ continue; } if ((entry.subvolume_name() == "@home") && !include_btrfs_home_for_restore){ continue; } } - + string dev_name = entry.device.full_name_with_parent; if (entry.subvolume_name().length > 0){ dev_name = dev_name + "(%s)".printf(entry.subvolume_name()); @@ -2154,7 +2154,7 @@ public class Main : GLib.Object{ else if (entry.lvm_name().length > 0){ dev_name = dev_name + "(%s)".printf(entry.lvm_name()); } - + if (dev_name.length > max_dev){ max_dev = dev_name.length; } @@ -2169,20 +2169,20 @@ public class Main : GLib.Object{ txt += string.nfill(max_dev, '-') + " " + string.nfill(max_mount, '-'); txt += "\n"; - + foreach(var entry in mount_list){ - + if (entry.device == null){ continue; } if (btrfs_mode){ if (entry.subvolume_name().length == 0){ continue; } - + if (!App.snapshot_to_restore.subvolumes.has_key(entry.subvolume_name())){ continue; } if ((entry.subvolume_name() == "@home") && !include_btrfs_home_for_restore){ continue; } } - + string dev_name = entry.device.full_name_with_parent; if (entry.subvolume_name().length > 0){ dev_name = dev_name + "(%s)".printf(entry.subvolume_name()); @@ -2190,7 +2190,7 @@ public class Main : GLib.Object{ else if (entry.lvm_name().length > 0){ dev_name = dev_name + "(%s)".printf(entry.lvm_name()); } - + txt += ("%%-%ds %%-%ds".printf(max_dev, max_mount)).printf(dev_name, entry.mount_point); txt += "\n"; @@ -2209,9 +2209,9 @@ public class Main : GLib.Object{ //msg += _("If restore fails and you are unable to boot the system, then boot from the Live CD, install Timeshift, and try to restore again.") + "\n"; // msg_reboot ----------------------- - + msg = ""; - if (restore_current_system){ + if (restore_current_system){ msg += _("Please save your work and close all applications.") + "\n"; msg += _("System will reboot after files are restored."); } @@ -2228,18 +2228,18 @@ public class Main : GLib.Object{ string.nfill(70,'=') ); } - + msg += _("This software comes without absolutely NO warranty and the author takes no responsibility for any damage arising from the use of this program."); msg += " " + _("If these terms are not acceptable to you, please do not proceed beyond this point!"); if (!formatted){ msg += "\n"; } - + msg_disclaimer = msg; // display messages in console mode - + if (app_mode.length > 0){ log_msg(msg_devices); log_msg(msg_reboot); @@ -2252,7 +2252,7 @@ public class Main : GLib.Object{ private void create_restore_scripts(out string sh_sync, out string sh_finish){ log_debug("Main: create_restore_scripts()"); - + string sh = ""; // create scripts -------------------------------------- @@ -2261,7 +2261,7 @@ public class Main : GLib.Object{ sh += "echo ''\n"; if (restore_current_system){ log_debug("restoring current system"); - + sh += "echo '" + _("Please do not interrupt the restore process!") + "'\n"; sh += "echo '" + _("System will reboot after files are restored") + "'\n"; } @@ -2275,7 +2275,7 @@ public class Main : GLib.Object{ if (dry_run){ sh += " --dry-run"; } - + sh += " --log-file=\"%s\"".printf(restore_log_file); sh += " --exclude-from=\"%s\"".printf(restore_exclude_file); @@ -2298,14 +2298,14 @@ public class Main : GLib.Object{ log_debug(sh); sh_sync = sh; - + // chroot and re-install grub2 --------------------- log_debug("reinstall_grub2=%s".printf(reinstall_grub2.to_string())); log_debug("grub_device=%s".printf((grub_device == null) ? "null" : grub_device)); var target_distro = LinuxDistro.get_dist_info(restore_target_path); - + sh = ""; string chroot = ""; @@ -2322,14 +2322,14 @@ public class Main : GLib.Object{ } if (reinstall_grub2 && (grub_device != null) && (grub_device.length > 0)){ - + sh += "sync \n"; sh += "echo '' \n"; sh += "echo '" + _("Re-installing GRUB2 bootloader...") + "' \n"; // search for other operating systems //sh += "chroot \"%s\" os-prober \n".printf(restore_target_path); - + // re-install grub --------------- if (target_distro.dist_type == "redhat"){ @@ -2339,7 +2339,7 @@ public class Main : GLib.Object{ sh += "%s grub2-install --recheck --force %s \n".printf(chroot, grub_device); /* NOTE: - * grub2-install should NOT be run on Fedora EFI systems + * grub2-install should NOT be run on Fedora EFI systems * https://fedoraproject.org/wiki/GRUB_2 * Instead following packages should be reinstalled: * dnf reinstall grub2-efi grub2-efi-modules shim @@ -2367,7 +2367,7 @@ public class Main : GLib.Object{ if (update_initramfs){ sh += "echo '' \n"; sh += "echo '" + _("Generating initramfs...") + "' \n"; - + if (target_distro.dist_type == "redhat"){ sh += "%s dracut -f -v \n".printf(chroot); } @@ -2378,13 +2378,13 @@ public class Main : GLib.Object{ sh += "%s update-initramfs -u -k all \n".printf(chroot); } } - + // update grub menu -------------- if (update_grub){ sh += "echo '' \n"; sh += "echo '" + _("Updating GRUB menu...") + "' \n"; - + if (target_distro.dist_type == "redhat"){ sh += "%s grub2-mkconfig -o /boot/grub2/grub.cfg \n".printf(chroot); } @@ -2398,12 +2398,12 @@ public class Main : GLib.Object{ sh += "sync \n"; sh += "echo '' \n"; } - + // sync file systems sh += "echo '" + _("Synching file systems...") + "' \n"; sh += "sync ; sleep 10s; \n"; sh += "echo '' \n"; - + if (!restore_current_system){ // unmount chrooted system sh += "echo '" + _("Cleaning up...") + "' \n"; @@ -2437,10 +2437,10 @@ public class Main : GLib.Object{ private bool restore_current_console(string sh_sync, string sh_finish){ log_debug("Main: restore_current_console()"); - + string script = sh_sync + sh_finish; int ret_val = -1; - + if (cmd_verbose){ //current/other system, console, verbose ret_val = exec_script_sync(script, null, null, false, false, false, true); @@ -2460,7 +2460,7 @@ public class Main : GLib.Object{ private bool restore_current_gui(string sh_sync, string sh_finish){ log_debug("Main: restore_current_gui()"); - + string script = sh_sync + sh_finish; string temp_script = save_bash_script_temp(script); @@ -2473,12 +2473,12 @@ public class Main : GLib.Object{ private bool restore_other_console(string sh_sync, string sh_finish){ log_debug("Main: restore_other_console()"); - + // execute sh_sync -------------------- - + string script = sh_sync; int ret_val = -1; - + if (cmd_verbose){ ret_val = exec_script_sync(script, null, null, false, false, false, true); log_msg(""); @@ -2491,7 +2491,7 @@ public class Main : GLib.Object{ } // update files ------------------- - + fix_fstab_file(restore_target_path); fix_crypttab_file(restore_target_path); @@ -2504,7 +2504,7 @@ public class Main : GLib.Object{ log_debug("executing sh_finish: "); log_debug(sh_finish); - + script = sh_finish; if (cmd_verbose){ @@ -2524,7 +2524,7 @@ public class Main : GLib.Object{ private bool restore_other_gui(string sh_sync, string sh_finish){ log_debug("Main: restore_other_gui()"); - + progress_text = _("Building file list..."); task = new RsyncTask(); @@ -2535,7 +2535,7 @@ public class Main : GLib.Object{ task.delete_after = true; task.dry_run = dry_run; - + if (mirror_system){ task.source_path = "/"; } @@ -2544,7 +2544,7 @@ public class Main : GLib.Object{ } task.dest_path = restore_target_path; - + task.exclude_from_file = restore_exclude_file; task.rsync_log_file = restore_log_file; @@ -2573,7 +2573,7 @@ public class Main : GLib.Object{ progress_text = _("Synching files with rsync..."); } } - + gtk_do_events(); } @@ -2599,7 +2599,7 @@ public class Main : GLib.Object{ log_debug("executing sh_finish: "); log_debug(sh_finish); - + int ret_val = exec_script_sync(sh_finish, null, null, false, false, false, true); log_debug("script exit code: %d".printf(ret_val)); @@ -2610,18 +2610,18 @@ public class Main : GLib.Object{ private void fix_fstab_file(string target_path){ log_debug("Main: fix_fstab_file()"); - + string fstab_path = path_combine(target_path, "etc/fstab"); if (!file_exists(fstab_path)){ log_debug("File not found: %s".printf(fstab_path)); return; } - + var fstab_list = FsTabEntry.read_file(fstab_path); log_debug("updating entries (1/2)..."); - + foreach(var mnt in mount_list){ // find existing var entry = FsTabEntry.find_entry_by_mount_point(fstab_list, mnt.mount_point); @@ -2652,18 +2652,18 @@ public class Main : GLib.Object{ * */ log_debug("updating entries(2/2)..."); - + for(int i = fstab_list.size - 1; i >= 0; i--){ var entry = fstab_list[i]; - + if (!entry.is_for_system_directory()){ continue; } - + var mnt = MountEntry.find_entry_by_mount_point(mount_list, entry.mount_point); if (mnt == null){ fstab_list.remove(entry); } } - + // write the updated file log_debug("writing updated file..."); @@ -2677,22 +2677,22 @@ public class Main : GLib.Object{ foreach(var entry in fstab_list){ if (entry.mount_point.length == 0){ continue; } if (!entry.mount_point.has_prefix("/")){ continue; } - + string mount_path = path_combine( target_path, entry.mount_point); - + if (entry.is_comment || entry.is_empty_line || (mount_path.length == 0)){ - + continue; } if (!dir_exists(mount_path)){ - + log_msg("Created mount point on target device: %s".printf( entry.mount_point)); - + dir_create(mount_path); } } @@ -2703,7 +2703,7 @@ public class Main : GLib.Object{ private void fix_crypttab_file(string target_path){ log_debug("Main: fix_crypttab_file()"); - + string crypttab_path = path_combine(target_path, "etc/crypttab"); if (!file_exists(crypttab_path)){ @@ -2712,11 +2712,11 @@ public class Main : GLib.Object{ } var crypttab_list = CryptTabEntry.read_file(crypttab_path); - + // add option "nofail" to existing entries log_debug("checking for 'nofail' option..."); - + foreach(var entry in crypttab_list){ entry.append_option("nofail"); } @@ -2724,10 +2724,10 @@ public class Main : GLib.Object{ log_debug("updating entries..."); // check and add entries for mapped devices which are encrypted - + foreach(var mnt in mount_list){ if ((mnt.device != null) && (mnt.device.parent != null) && (mnt.device.is_on_encrypted_partition())){ - + // find existing var entry = CryptTabEntry.find_entry_by_uuid( crypttab_list, mnt.device.parent.uuid); @@ -2737,7 +2737,7 @@ public class Main : GLib.Object{ entry = new CryptTabEntry(); crypttab_list.add(entry); } - + // set custom values entry.device_uuid = mnt.device.parent.uuid; entry.mapped_name = "luks-%s".printf(mnt.device.parent.uuid); @@ -2756,7 +2756,7 @@ public class Main : GLib.Object{ } private void check_and_repair_filesystems(){ - + if (!restore_current_system){ string sh_fsck = "echo '" + _("Checking file systems for errors...") + "' \n"; foreach(var mnt in mount_list){ @@ -2770,22 +2770,22 @@ public class Main : GLib.Object{ } public bool restore_execute_rsync(){ - + log_debug("Main: restore_execute_rsync()"); try{ log_debug("source_path=%s".printf(restore_source_path)); log_debug("target_path=%s".printf(restore_target_path)); - + string sh_sync, sh_finish; create_restore_scripts(out sh_sync, out sh_finish); - + save_exclude_list_for_restore(restore_source_path); file_delete(restore_log_file); file_delete(restore_log_file + "-changes"); file_delete(restore_log_file + ".gz"); - + if (restore_current_system){ string control_file_path = path_combine(snapshot_to_restore.path,".sync-restore"); @@ -2798,7 +2798,7 @@ public class Main : GLib.Object{ } // run the scripts -------------------- - + if (snapshot_to_restore != null){ if (dry_run){ log_msg(_("Comparing Files (Dry Run)...")); @@ -2815,7 +2815,7 @@ public class Main : GLib.Object{ log_msg(progress_text); bool ok = true; - + if (app_mode == ""){ // GUI if (!restore_current_system || dry_run){ ok = restore_other_gui(sh_sync, sh_finish); @@ -2853,33 +2853,33 @@ public class Main : GLib.Object{ thread_restore_running = false; return thr_success; } - + public bool restore_execute_btrfs(){ log_debug("Main: restore_execute_btrfs()"); - + bool ok = create_pre_restore_snapshot_btrfs(); log_msg(string.nfill(78, '-')); - + if (!ok){ thread_restore_running = false; thr_success = false; return thr_success; } - + // restore snapshot subvolumes by creating new subvolume snapshots foreach(var subvol in snapshot_to_restore.subvolumes.values){ if ((subvol.name == "@home") && !include_btrfs_home_for_restore){ continue; } - + subvol.restore(); } log_msg(_("Restore completed")); thr_success = true; - + if (restore_current_system){ log_msg(_("Snapshot will become active after system is rebooted.")); } @@ -2895,13 +2895,13 @@ public class Main : GLib.Object{ public bool create_pre_restore_snapshot_btrfs(){ log_debug("Main: create_pre_restore_snapshot_btrfs()"); - + string cmd, std_out, std_err; DateTime dt_created = new DateTime.now_local(); string time_stamp = dt_created.format("%Y-%m-%d_%H-%M-%S"); string snapshot_name = time_stamp; string snapshot_path = ""; - + /* Note: * The @ and @home subvolumes need to be backed-up only if they are in use by the system. * If user restores a snapshot and then tries to restore another snapshot before the next reboot @@ -2911,7 +2911,7 @@ public class Main : GLib.Object{ bool create_pre_restore_backup = false; if (restore_current_system){ - + // check for an existing pre-restore backup Snapshot snap_prev = null; @@ -2951,11 +2951,11 @@ public class Main : GLib.Object{ if (create_pre_restore_backup){ log_msg(_("Creating pre-restore snapshot from system subvolumes...")); - + dir_create(snapshot_path); // move subvolumes ---------------- - + bool no_subvolumes_found = true; var subvol_list = new Gee.ArrayList(); @@ -2964,27 +2964,27 @@ public class Main : GLib.Object{ if (include_btrfs_home_for_restore){ subvol_names = new string[] { "@","@home" }; } - + foreach(string subvol_name in subvol_names){ snapshot_path = path_combine(repo.mount_paths[subvol_name], "timeshift-btrfs/snapshots/%s".printf(snapshot_name)); dir_create(snapshot_path, true); - + string src_path = path_combine(repo.mount_paths[subvol_name], subvol_name); if (!dir_exists(src_path)){ log_error(_("Could not find system subvolume") + ": %s".printf(subvol_name)); dir_delete(snapshot_path); continue; } - + no_subvolumes_found = false; string dst_path = path_combine(snapshot_path, subvol_name); cmd = "mv '%s' '%s'".printf(src_path, dst_path); log_debug(cmd); - + int status = exec_sync(cmd, out std_out, out std_err); - + if (status != 0){ log_error (std_err); log_error(_("Failed to move system subvolume to snapshot directory") + ": %s".printf(subvol_name)); @@ -2993,7 +2993,7 @@ public class Main : GLib.Object{ else{ var subvol_dev = (subvol_name == "@") ? repo.device : repo.device_home; subvol_list.add(new Subvolume(subvol_name, dst_path, subvol_dev.uuid, repo)); - + log_msg(_("Moved system subvolume to snapshot directory") + ": %s".printf(subvol_name)); } } @@ -3006,7 +3006,7 @@ public class Main : GLib.Object{ // write control file ----------- snapshot_path = path_combine(repo.mount_paths["@"], "timeshift-btrfs/snapshots/%s".printf(snapshot_name)); - + var snap = Snapshot.write_control_file( snapshot_path, dt_created, repo.device.uuid, LinuxDistro.get_dist_info(path_combine(snapshot_path,"@")).full_name(), @@ -3014,36 +3014,36 @@ public class Main : GLib.Object{ snap.description = "Before restoring '%s'".printf(snapshot_to_restore.date_formatted); snap.live = true; - + // write subvolume info foreach(var subvol in subvol_list){ snap.subvolumes.set(subvol.name, subvol); } - + snap.update_control_file(); // save subvolume info log_msg(_("Created pre-restore snapshot") + ": %s".printf(snap.name)); - + repo.load_snapshots(); } } return true; } - + //app config public void save_app_config(){ log_debug("Main: save_app_config()"); - + var config = new Json.Object(); - + if ((repo != null) && repo.available()){ // save backup device uuid config.set_string_member("backup_device_uuid", (repo.device == null) ? "" : repo.device.uuid); - + // save parent uuid if backup device has parent config.set_string_member("parent_device_uuid", (repo.device.has_parent()) ? repo.device.parent.uuid : ""); @@ -3051,7 +3051,7 @@ public class Main : GLib.Object{ else{ // retain values for next run config.set_string_member("backup_device_uuid", backup_uuid); - config.set_string_member("parent_device_uuid", backup_parent_uuid); + config.set_string_member("parent_device_uuid", backup_parent_uuid); } config.set_string_member("do_first_run", false.to_string()); @@ -3077,7 +3077,7 @@ public class Main : GLib.Object{ config.set_string_member("snapshot_count", first_snapshot_count.to_string()); config.set_string_member("date_format", date_format); - + Json.Array arr = new Json.Array(); foreach(string path in exclude_list_user){ arr.add_string_element(path); @@ -3113,11 +3113,11 @@ public class Main : GLib.Object{ log_debug("Main: load_app_config()"); // check if first run ----------------------- - + var f = File.new_for_path(this.app_conf_path); - + if (!f.query_exists()) { - + if (file_exists(app_conf_path_old)){ // move old file file_move(app_conf_path_old, app_conf_path); @@ -3127,9 +3127,9 @@ public class Main : GLib.Object{ file_copy(app_conf_path_default, app_conf_path); } } - + // load settings from config file -------------------------- - + var parser = new Json.Parser(); try{ parser.load_from_file(this.app_conf_path); @@ -3142,29 +3142,29 @@ public class Main : GLib.Object{ bool do_first_run = json_get_bool(config, "do_first_run", false); // false as default btrfs_mode = json_get_bool(config, "btrfs_mode", false); // false as default - + if (do_first_run){ set_first_run_flag(); } - + if (config.has_member("include_btrfs_home")){ include_btrfs_home_for_backup = json_get_bool(config, "include_btrfs_home", include_btrfs_home_for_backup); } else{ include_btrfs_home_for_backup = json_get_bool(config, "include_btrfs_home_for_backup", include_btrfs_home_for_backup); } - + include_btrfs_home_for_restore = json_get_bool(config, "include_btrfs_home_for_restore", include_btrfs_home_for_restore); stop_cron_emails = json_get_bool(config, "stop_cron_emails", stop_cron_emails); btrfs_use_qgroup = json_get_bool(config, "btrfs_use_qgroup", btrfs_use_qgroup); - + if (cmd_btrfs_mode != null){ btrfs_mode = cmd_btrfs_mode; //override } - + backup_uuid = json_get_string(config,"backup_device_uuid", backup_uuid); backup_parent_uuid = json_get_string(config,"parent_device_uuid", backup_parent_uuid); - + this.schedule_monthly = json_get_bool(config,"schedule_monthly",schedule_monthly); this.schedule_weekly = json_get_bool(config,"schedule_weekly",schedule_weekly); this.schedule_daily = json_get_bool(config,"schedule_daily",schedule_daily); @@ -3180,21 +3180,21 @@ public class Main : GLib.Object{ this.date_format = json_get_string(config, "date_format", date_format_default); Main.first_snapshot_size = json_get_uint64(config,"snapshot_size", Main.first_snapshot_size); - + Main.first_snapshot_count = (int64) json_get_uint64(config,"snapshot_count", Main.first_snapshot_count); - + exclude_list_user.clear(); - + if (config.has_member ("exclude")){ - + foreach (Json.Node jnode in config.get_array_member ("exclude").get_elements()) { - + string path = jnode.get_string(); - + if (!exclude_list_user.contains(path) && !exclude_list_default.contains(path) && !exclude_list_home.contains(path)){ - + exclude_list_user.add(path); } } @@ -3203,13 +3203,13 @@ public class Main : GLib.Object{ exclude_app_names.clear(); if (config.has_member ("exclude-apps")){ - + var apps = config.get_array_member("exclude-apps"); - + foreach (Json.Node jnode in apps.get_elements()) { - + string name = jnode.get_string(); - + if (!exclude_app_names.contains(name)){ exclude_app_names.add(name); } @@ -3222,13 +3222,13 @@ public class Main : GLib.Object{ } public void set_first_run_flag(){ - + first_run = true; - + log_msg("First run mode (config file not found)"); // load some defaults for first-run based on user's system type - + bool supported = sys_subvolumes.has_key("@") && cmd_exists("btrfs"); // && sys_subvolumes.has_key("@home") if (supported || (cmd_btrfs_mode == true)){ log_msg(_("Selected default snapshot type") + ": %s".printf("BTRFS")); @@ -3239,11 +3239,11 @@ public class Main : GLib.Object{ btrfs_mode = false; } } - + public void initialize_repo(){ log_debug("Main: initialize_repo()"); - + log_debug("backup_uuid=%s".printf(backup_uuid)); log_debug("backup_parent_uuid=%s".printf(backup_parent_uuid)); @@ -3276,7 +3276,7 @@ public class Main : GLib.Object{ } // select default device for first run mode else if (first_run && (backup_uuid.length == 0)){ - + try_select_default_device_for_backup(parent_window); if ((repo != null) && (repo.device != null)){ @@ -3285,7 +3285,7 @@ public class Main : GLib.Object{ } else { log_debug("Setting snapshot device from config file"); - + // find devices from uuid Device dev = null; Device dev_parent = null; @@ -3301,7 +3301,7 @@ public class Main : GLib.Object{ log_debug("Snapshot device is on an encrypted partition"); repo = new SnapshotRepo.from_uuid(backup_parent_uuid, parent_window, btrfs_mode); } - // try device + // try device else if (dev != null){ log_debug("repo: creating from uuid"); repo = new SnapshotRepo.from_uuid(backup_uuid, parent_window, btrfs_mode); @@ -3329,15 +3329,15 @@ public class Main : GLib.Object{ log_debug("Main: initialize_repo(): exit"); } - + //core functions public void update_partitions(){ log_debug("update_partitions()"); - + partitions.clear(); - + partitions = Device.get_filesystems(); foreach(var pi in partitions){ @@ -3346,12 +3346,12 @@ public class Main : GLib.Object{ if ((repo != null) && (repo.device != null) && (pi.uuid == repo.device.uuid)){ repo.device = pi; } - + if (pi.is_mounted){ pi.dist_info = LinuxDistro.get_dist_info(pi.mount_points[0].mount_point).full_name(); } } - + if (partitions.size == 0){ log_error("ts: " + _("Failed to get partition list.")); } @@ -3369,9 +3369,9 @@ public class Main : GLib.Object{ sys_home = null; foreach(var pi in partitions){ - + foreach(var mp in pi.mount_points){ - + // skip loop devices - Fedora Live uses loop devices containing ext4-formatted lvm volumes if ((pi.type == "loop") || (pi.has_parent() && (pi.parent.type == "loop"))){ continue; @@ -3434,11 +3434,11 @@ public class Main : GLib.Object{ * */ log_debug("mount_target_device()"); - + if (dst_root == null){ return false; } - + //check and create restore mount point for restore mount_point_restore = mount_point_app + "/restore"; dir_create(mount_point_restore); @@ -3451,13 +3451,13 @@ public class Main : GLib.Object{ foreach(var mp in dev_mounted.mount_points){ if ((mp.mount_point == mount_point_restore) && (mp.mount_options == "subvol=@")){ - + = true; return; //already_mounted } } }*/ - + // unmount unmount_target_device(); @@ -3467,7 +3467,7 @@ public class Main : GLib.Object{ //check subvolume layout bool supported = check_btrfs_layout(dst_root, dst_home, false); - + if (!supported && snapshot_to_restore.has_subvolumes()){ string msg = _("The target partition has an unsupported subvolume layout.") + "\n"; msg += _("Only ubuntu-type layouts with @ and @home subvolumes are currently supported."); @@ -3490,7 +3490,7 @@ public class Main : GLib.Object{ if (mnt.device == null){ continue; } - + // unlock encrypted device if (mnt.device.is_encrypted_partition()){ @@ -3501,7 +3501,7 @@ public class Main : GLib.Object{ else{ // prompt user string msg_out, msg_err; - + var dev_unlocked = Device.luks_unlock( mnt.device, "", "", parent_win, out msg_out, out msg_err); @@ -3516,7 +3516,7 @@ public class Main : GLib.Object{ } string mount_options = ""; - + if (mnt.device.fstype == "btrfs"){ if (mnt.mount_point == "/"){ mount_options = "subvol=@"; @@ -3537,11 +3537,11 @@ public class Main : GLib.Object{ } public void unmount_target_device(bool exit_on_error = true){ - + if (mount_point_restore == null) { return; } log_debug("unmount_target_device()"); - + //unmount the target device only if it was mounted by application if (mount_point_restore.has_prefix(mount_point_app)){ //always true unmount_device(mount_point_restore, exit_on_error); @@ -3576,23 +3576,23 @@ public class Main : GLib.Object{ public bool check_btrfs_volume(Device dev, string subvol_names, bool unlock){ log_debug("check_btrfs_volume():%s".printf(subvol_names)); - + string mnt_btrfs = mount_point_app + "/btrfs"; dir_create(mnt_btrfs); if (!dev.is_mounted_at_path("", mnt_btrfs)){ - + Device.unmount(mnt_btrfs); // unlock encrypted device if (dev.is_encrypted_partition()){ if (unlock){ - + string msg_out, msg_err; var dev_unlocked = Device.luks_unlock( dev, "", "", parent_window, out msg_out, out msg_err); - + if (dev_unlocked == null){ log_debug("device is null"); log_debug("SnapshotRepo: check_btrfs_volume(): exit"); @@ -3644,7 +3644,7 @@ public class Main : GLib.Object{ repo = new SnapshotRepo.from_null(); } } - + update_partitions(); // In BTRFS mode, select the system disk if system disk is BTRFS @@ -3653,7 +3653,7 @@ public class Main : GLib.Object{ repo = new SnapshotRepo.from_device(subvol_root.get_device(), parent_win, btrfs_mode); return; } - + foreach(var dev in partitions){ if (check_device_for_backup(dev, false)){ repo = new SnapshotRepo.from_device(dev, parent_win, btrfs_mode); @@ -3670,7 +3670,7 @@ public class Main : GLib.Object{ if (dev.type == "disk") { return false; } if (dev.has_children()) { return false; } - + if (btrfs_mode && ((dev.fstype == "btrfs")||(dev.fstype == "luks"))){ if (check_btrfs_volume(dev, "@", unlock)){ return true; @@ -3683,11 +3683,11 @@ public class Main : GLib.Object{ return ok; } - + public uint64 estimate_system_size(){ log_debug("estimate_system_size()"); - + if (Main.first_snapshot_size > 0){ return Main.first_snapshot_size; } @@ -3713,7 +3713,7 @@ public class Main : GLib.Object{ save_app_config(); log_debug("estimate_system_size(): ok"); - + return Main.first_snapshot_size; } @@ -3750,7 +3750,7 @@ public class Main : GLib.Object{ } save_exclude_list_for_backup(TEMP_DIR); - + cmd = "LC_ALL=C ; rsync -ai --delete --numeric-ids --relative --stats --dry-run --delete-excluded --exclude-from='%s' /. '%s' &> '%s'".printf(file_exclude_list, dir_empty, file_log); log_debug(cmd); @@ -3767,7 +3767,7 @@ public class Main : GLib.Object{ if (ret_val == 0){ file_count = long.parse(std_out.split(" ")[0].strip()); } - + thr_success = true; } else{ @@ -3810,13 +3810,13 @@ public class Main : GLib.Object{ repo = parent_repo; // TODO: move query_subvolume_info() and related methods to SnapshotRepo - + if ((repo == null) || !repo.btrfs_mode){ return; } - + log_debug(_("Querying subvolume info...")); - + try { thread_subvol_info_running = true; thread_subvol_info_success = false; @@ -3836,12 +3836,12 @@ public class Main : GLib.Object{ } public void query_subvolume_info_thread(){ - + thread_subvol_info_running = true; //query IDs bool ok = query_subvolume_ids(); - + if (!ok){ thread_subvol_info_success = false; thread_subvol_info_running = false; @@ -3850,11 +3850,11 @@ public class Main : GLib.Object{ //query quota ok = query_subvolume_quotas(); - + if (!ok){ if (btrfs_use_qgroup){ - + //try enabling quota ok = enable_subvolume_quotas(); if (!ok){ @@ -3885,11 +3885,11 @@ public class Main : GLib.Object{ } return ok; } - + public bool query_subvolume_id(string subvol_name){ log_debug("query_subvolume_id():%s".printf(subvol_name)); - + string cmd = ""; string std_out; string std_err; @@ -3925,7 +3925,7 @@ public class Main : GLib.Object{ else if ((sys_subvolumes.size > 0) && sys_subvolumes.has_key("@home") && line.has_suffix(sys_subvolumes["@home"].path.replace(repo.mount_paths["@home"] + "/"," "))){ - + subvol = sys_subvolumes["@home"]; } else { @@ -3955,24 +3955,24 @@ public class Main : GLib.Object{ } return ok; } - + public bool query_subvolume_quota(string subvol_name){ log_debug("query_subvolume_quota():%s".printf(subvol_name)); - + string cmd = ""; string std_out; string std_err; int ret_val; string options = use_option_raw ? "--raw" : ""; - + cmd = "btrfs qgroup show %s '%s'".printf(options, repo.mount_paths[subvol_name]); log_debug(cmd); ret_val = exec_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ - + if (use_option_raw){ use_option_raw = false; @@ -3980,8 +3980,8 @@ public class Main : GLib.Object{ cmd = "btrfs qgroup show '%s'".printf(repo.mount_paths[subvol_name]); log_debug(cmd); ret_val = exec_sync(cmd, out std_out, out std_err); - } - + } + if (ret_val != 0){ log_error (std_err); log_error(_("btrfs returned an error") + ": %d".printf(ret_val)); @@ -4011,13 +4011,13 @@ public class Main : GLib.Object{ Subvolume subvol = null; if ((sys_subvolumes.size > 0) && (sys_subvolumes["@"].id == subvol_id)){ - + subvol = sys_subvolumes["@"]; } else if ((sys_subvolumes.size > 0) && sys_subvolumes.has_key("@home") && (sys_subvolumes["@home"].id == subvol_id)){ - + subvol = sys_subvolumes["@home"]; } else { @@ -4061,25 +4061,25 @@ public class Main : GLib.Object{ public bool enable_subvolume_quotas(){ if (!btrfs_use_qgroup){ return false; } - + bool ok = enable_subvolume_quota("@"); - + if (repo.device.uuid != repo.device_home.uuid){ ok = ok && enable_subvolume_quota("@home"); } if (ok){ log_msg(_("Enabled subvolume quota support")); } - + return ok; } - + public bool enable_subvolume_quota(string subvol_name){ if (!btrfs_use_qgroup){ return false; } - + log_debug("enable_subvolume_quota():%s".printf(subvol_name)); - + string cmd = ""; string std_out; string std_err; @@ -4087,9 +4087,9 @@ public class Main : GLib.Object{ cmd = "btrfs quota enable '%s'".printf(repo.mount_paths[subvol_name]); log_debug(cmd); - + ret_val = exec_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ log_error (std_err); log_error(_("btrfs returned an error") + ": %d".printf(ret_val)); @@ -4101,23 +4101,23 @@ public class Main : GLib.Object{ } public bool rescan_subvolume_quotas(){ - + bool ok = rescan_subvolume_quota("@"); - + if (repo.device.uuid != repo.device_home.uuid){ ok = ok && rescan_subvolume_quota("@home"); } if (ok){ log_msg(_("Enabled subvolume quota support")); } - + return ok; } - + public bool rescan_subvolume_quota(string subvol_name){ log_debug("rescan_subvolume_quota():%s".printf(subvol_name)); - + string cmd = ""; string std_out; string std_err; @@ -4125,11 +4125,11 @@ public class Main : GLib.Object{ cmd = "btrfs quota rescan '%s'".printf(repo.mount_paths[subvol_name]); log_debug(cmd); - + ret_val = exec_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ - + log_error (std_err); log_error(_("btrfs returned an error") + ": %d".printf(ret_val)); log_error(_("Failed to rescan subvolume quota")); @@ -4142,18 +4142,18 @@ public class Main : GLib.Object{ // cron jobs public void cron_job_update(){ - + if (live_system()) { return; } // remove entries created by previous versions ----------- - + string entry = "timeshift --backup"; int count = 0; while (CronTab.has_job(entry, true, false)){ - + CronTab.remove_job(entry, true, true); - + if (++count == 100){ break; } @@ -4163,23 +4163,23 @@ public class Main : GLib.Object{ count = 0; while (CronTab.has_job(entry, true, false)){ - + CronTab.remove_job(entry, true, true); - + if (++count == 100){ break; } } CronTab.remove_script_file("timeshift-hourly", "hourly"); - + // start update --------------------------- - + if (scheduled){ - + //hourly CronTab.add_script_file("timeshift-hourly", "d", "0 * * * * root timeshift --check --scripted", stop_cron_emails); - + //boot if (schedule_boot){ CronTab.add_script_file("timeshift-boot", "d", "@reboot root sleep 10m && timeshift --create --scripted --tags B", stop_cron_emails); @@ -4193,13 +4193,13 @@ public class Main : GLib.Object{ CronTab.remove_script_file("timeshift-boot", "d"); } } - + // cleanup public void clean_logs(){ log_debug("clean_logs()"); - + Gee.ArrayList list = new Gee.ArrayList(); try{ @@ -4230,15 +4230,15 @@ public class Main : GLib.Object{ // delete oldest 100 files --------------- for(int k = 0; k < 100; k++){ - + var file = File.new_for_path (list[k]); - - if (file.query_exists()){ + + if (file.query_exists()){ file.delete(); log_msg("%s: %s".printf(_("Removed"), list[k])); } } - + log_msg(_("Older log files removed")); } } @@ -4250,7 +4250,7 @@ public class Main : GLib.Object{ public void exit_app (int exit_code = 0){ log_debug("exit_app()"); - + if (app_mode == ""){ //update app config only in GUI mode save_app_config(); @@ -4263,7 +4263,7 @@ public class Main : GLib.Object{ clean_logs(); app_lock.remove(); - + dir_delete(TEMP_DIR); exit(exit_code); diff --git a/src/Core/Snapshot.vala b/src/Core/Snapshot.vala index 1574a13..cae83d4 100644 --- a/src/Core/Snapshot.vala +++ b/src/Core/Snapshot.vala @@ -32,7 +32,7 @@ using TeeJee.Misc; using Json; public class Snapshot : GLib.Object{ - + public string path = ""; public string name = ""; public DateTime date; @@ -51,13 +51,13 @@ public class Snapshot : GLib.Object{ public bool marked_for_deletion = false; public LinuxDistro distro; public SnapshotRepo repo; - + //btrfs public bool btrfs_mode = false; public Gee.HashMap paths; // for btrfs snapshots only public string mount_path_root = ""; public string mount_path_home = ""; - + public DeleteFileTask delete_file_task; public Snapshot(string dir_path, bool btrfs_snapshot, SnapshotRepo _repo){ @@ -71,7 +71,7 @@ public class Snapshot : GLib.Object{ description = ""; btrfs_mode = btrfs_snapshot; repo = _repo; - + date = new DateTime.from_unix_utc(0); tags = new Gee.ArrayList(); exclude_list = new Gee.ArrayList(); @@ -79,7 +79,7 @@ public class Snapshot : GLib.Object{ delete_file_task = new DeleteFileTask(); subvolumes = new Gee.HashMap(); paths = new Gee.HashMap(); - + read_control_file(); read_exclude_list(); read_fstab_file(); @@ -91,7 +91,7 @@ public class Snapshot : GLib.Object{ } // properties - + public string date_formatted{ owned get{ return date.format(App.date_format);//.format("%Y-%m-%d %H:%M:%S"); @@ -101,41 +101,41 @@ public class Snapshot : GLib.Object{ public string rsync_log_file{ owned get { return path_combine(path, "rsync-log"); - } + } } public string rsync_changes_log_file{ owned get { return path_combine(path, "rsync-log-changes"); - } + } } public string rsync_restore_log_file{ owned get { return path_combine(path, "rsync-log-restore"); - } + } } public string rsync_restore_changes_log_file{ owned get { return path_combine(path, "rsync-log-restore-changes"); - } + } } - + public string exclude_file_for_backup { owned get { return path_combine(path, "exclude.list"); - } + } } public string exclude_file_for_restore { owned get { return path_combine(path, "exclude-restore.list"); - } + } } - + // manage tags - + public string taglist{ owned get{ string str = ""; @@ -165,7 +165,7 @@ public class Snapshot : GLib.Object{ } public void add_tag(string tag){ - + if (!tags.contains(tag.strip())){ tags.add(tag.strip()); update_control_file(); @@ -173,7 +173,7 @@ public class Snapshot : GLib.Object{ } public void remove_tag(string tag){ - + if (tags.contains(tag.strip())){ tags.remove(tag.strip()); update_control_file(); @@ -181,30 +181,30 @@ public class Snapshot : GLib.Object{ } public bool has_tag(string tag){ - + return tags.contains(tag.strip()); } // control files - + public void read_control_file(){ - + //log_debug("read_control_file()"); - + string ctl_file = path + "/info.json"; var f = File.new_for_path(ctl_file); - + if (f.query_exists()) { - + var parser = new Json.Parser(); - + try{ parser.load_from_file(ctl_file); } catch (Error e) { log_error (e.message); } - + var node = parser.get_root(); var config = node.get_object(); @@ -236,24 +236,24 @@ public class Snapshot : GLib.Object{ var subvols = (Json.Object) config.get_object_member("subvolumes"); foreach(string subvol_name in subvols.get_members()){ - + if ((subvol_name != "@")&&(subvol_name != "@home")){ continue; } - + paths[subvol_name] = path.replace(repo.mount_path, repo.mount_paths[subvol_name]); - + var subvol_path = path_combine(paths[subvol_name], subvol_name); - + if (!dir_exists(subvol_path)){ continue; } //log_debug("subvol_path: %s".printf(subvol_path)); - + var subvolume = new Subvolume(subvol_name, subvol_path, "", repo); //subvolumes.get(subvol_name); subvolumes.set(subvol_name, subvolume); - + int index = -1; - + foreach(Json.Node jnode in subvols.get_array_member(subvol_name).get_elements()) { - + string item = jnode.get_string(); switch (++index){ case 0: @@ -275,7 +275,7 @@ public class Snapshot : GLib.Object{ } } } - + string delete_trigger_file = path + "/delete"; if (file_exists(delete_trigger_file)){ marked_for_deletion = true; @@ -284,24 +284,24 @@ public class Snapshot : GLib.Object{ else{ valid = false; } - + //log_debug("read_control_file(): exit"); } public void read_exclude_list(){ - + string list_file = path + "/exclude.list"; exclude_list.clear(); var f = File.new_for_path(list_file); - + if (f.query_exists()) { - + foreach(string path in file_read(list_file).split("\n")){ - + path = path.strip(); - + if (!exclude_list.contains(path) && path.length > 0){ exclude_list.add(path); } @@ -315,30 +315,30 @@ public class Snapshot : GLib.Object{ } public void read_fstab_file(){ - + string fstab_path = path_combine(path, "/localhost/etc/fstab"); - + if (btrfs_mode){ fstab_path = path_combine(path, "/@/etc/fstab"); } - + fstab_list = FsTabEntry.read_file(fstab_path); } public void read_crypttab_file(){ - + string crypttab_path = path_combine(path, "/localhost/etc/crypttab"); - + if (btrfs_mode){ crypttab_path = path_combine(path, "/@/etc/crypttab"); } - + cryttab_list = CryptTabEntry.read_file(crypttab_path); } public void update_control_file(){ /* Updates tag and comments */ - + try{ string ctl_file = path + "/info.json"; var f = File.new_for_path(ctl_file); @@ -371,7 +371,7 @@ public class Snapshot : GLib.Object{ subvols.set_array_member(subvol.name,arr); } } - + var json = new Json.Generator(); json.pretty = true; json.indent = 2; @@ -386,15 +386,15 @@ public class Snapshot : GLib.Object{ } public void remove_control_file(){ - + string ctl_file = path + "/info.json"; file_delete(ctl_file); } - + public static Snapshot write_control_file( - string snapshot_path, DateTime dt_created, string root_uuid, string distro_full_name, + string snapshot_path, DateTime dt_created, string root_uuid, string distro_full_name, string tag, string comments, int64 item_count, bool is_btrfs, bool is_live, SnapshotRepo repo, bool silent = false){ - + var ctl_path = snapshot_path + "/info.json"; var config = new Json.Object(); @@ -434,7 +434,7 @@ public class Snapshot : GLib.Object{ } // check - + public bool has_subvolumes(){ foreach(FsTabEntry en in fstab_list){ if (en.options.contains("subvol=@")){ @@ -456,7 +456,7 @@ public class Snapshot : GLib.Object{ return list; } } - + // actions public bool remove(bool wait){ @@ -466,7 +466,7 @@ public class Snapshot : GLib.Object{ } bool status = true; - + if (btrfs_mode){ status = remove_btrfs(); } @@ -476,21 +476,21 @@ public class Snapshot : GLib.Object{ return status; } - + public bool remove_rsync(bool wait){ log_msg(string.nfill(78, '-')); - + var message = _("Removing") + " '%s'...".printf(name); log_msg(message); - + delete_file_task.dest_path = "%s/".printf(path); delete_file_task.status_message = message; delete_file_task.prg_count_total = Main.first_snapshot_count; delete_file_task.execute(); if (wait){ - + while (delete_file_task.status == AppStatus.RUNNING){ sleep(1000); @@ -499,14 +499,14 @@ public class Snapshot : GLib.Object{ stdout.printf("%6.2f%% %s (%s %s)\r".printf( delete_file_task.progress * 100.0, _("complete"), delete_file_task.stat_time_remaining, _("remaining"))); - + stdout.flush(); } stdout.printf(string.nfill(80, ' ') + "\r"); stdout.flush(); - message = "%s '%s'".printf(_("Removed"), name); + message = "%s '%s'".printf(_("Removed"), name); log_msg(message); log_msg(string.nfill(78, '-')); } @@ -517,14 +517,14 @@ public class Snapshot : GLib.Object{ public bool remove_btrfs(){ log_msg(string.nfill(78, '-')); - + var message = _("Removing snapshot") + ": %s".printf(name); log_msg(message); - + // delete subvolumes - + foreach(var subvol in subvolumes.values){ - + bool ok = subvol.remove(); if (!ok) { log_error(_("Failed to remove snapshot") + ": %s".printf(name)); @@ -536,7 +536,7 @@ public class Snapshot : GLib.Object{ // delete directories after **all** subvolumes have been deleted foreach(var subvol in subvolumes.values){ - + bool ok = dir_delete(paths[subvol.name], true); if (!ok) { log_error(_("Failed to remove snapshot") + ": %s".printf(name)); @@ -546,7 +546,7 @@ public class Snapshot : GLib.Object{ } if (!dir_delete(path, true)){ - + log_error(_("Failed to remove snapshot") + ": %s".printf(name)); log_msg(string.nfill(78, '-')); return false; @@ -554,14 +554,14 @@ public class Snapshot : GLib.Object{ log_msg(_("Removed snapshot") + ": %s".printf(name)); log_msg(string.nfill(78, '-')); - + return true; } - + public void mark_for_deletion(){ - + string delete_trigger_file = path + "/delete"; - + if (!file_exists(delete_trigger_file)){ file_write(delete_trigger_file, ""); marked_for_deletion = true; diff --git a/src/Core/SnapshotRepo.vala b/src/Core/SnapshotRepo.vala index 028ba45..3cdafb2 100755 --- a/src/Core/SnapshotRepo.vala +++ b/src/Core/SnapshotRepo.vala @@ -30,7 +30,7 @@ using TeeJee.System; using TeeJee.Misc; public class SnapshotRepo : GLib.Object{ - + public Device device = null; public Device device_home = null; // used for btrfs mode only public string mount_path = ""; @@ -53,46 +53,46 @@ public class SnapshotRepo : GLib.Object{ public SnapshotRepo.from_path(string path, Gtk.Window? parent_win, bool _btrfs_mode){ log_debug("SnapshotRepo: from_path()"); - + //this.snapshot_path_user = path; //this.use_snapshot_path_custom = true; this.mount_path = path; this.parent_window = parent_win; this.btrfs_mode = _btrfs_mode; - + snapshots = new Gee.ArrayList(); invalid_snapshots = new Gee.ArrayList(); mount_paths = new Gee.HashMap(); - + //log_debug("Selected snapshot repo path: %s".printf(path)); - + var list = Device.get_disk_space_using_df(path); - + if (list.size > 0){ - + device = list[0]; - + log_debug(_("Device") + ": %s".printf(device.device)); log_debug(_("Free space") + ": %s".printf(format_file_size(device.free_bytes))); } - + check_status(); } public SnapshotRepo.from_device(Device dev, Gtk.Window? parent_win, bool btrfs_repo){ log_debug("SnapshotRepo: from_device(): %s".printf(btrfs_repo ? "BTRFS" : "RSYNC")); - + this.device = dev; //this.use_snapshot_path_custom = false; this.parent_window = parent_win; this.btrfs_mode = btrfs_repo; - + snapshots = new Gee.ArrayList(); invalid_snapshots = new Gee.ArrayList(); mount_paths = new Gee.HashMap(); - + init_from_device(); } @@ -100,17 +100,17 @@ public class SnapshotRepo : GLib.Object{ log_debug("SnapshotRepo: from_uuid(): %s".printf(btrfs_repo ? "BTRFS" : "RSYNC")); log_debug("uuid=%s".printf(uuid)); - + device = Device.get_device_by_uuid(uuid); if (device == null){ device = new Device(); device.uuid = uuid; } - + //this.use_snapshot_path_custom = false; this.parent_window = parent_win; this.btrfs_mode = btrfs_repo; - + snapshots = new Gee.ArrayList(); invalid_snapshots = new Gee.ArrayList(); mount_paths = new Gee.HashMap(); @@ -124,7 +124,7 @@ public class SnapshotRepo : GLib.Object{ log_debug("SnapshotRepo: from_null()"); log_debug("device not set"); - + snapshots = new Gee.ArrayList(); invalid_snapshots = new Gee.ArrayList(); mount_paths = new Gee.HashMap(); @@ -135,21 +135,21 @@ public class SnapshotRepo : GLib.Object{ private void init_from_device(){ log_debug("SnapshotRepo: init_from_device()"); - + if ((device != null) && (device.uuid.length > 0) && (Device.get_device_by_uuid(device.uuid) != null)){ - + log_debug(""); unlock_and_mount_devices(); if ((device != null) && (device.device.length > 0)){ - + log_debug(_("Selected snapshot device") + ": %s".printf(device.device)); log_debug(_("Free space") + ": %s".printf(format_file_size(device.free_bytes))); } } if ((device != null) && (device.device.length > 0)){ - + check_status(); } @@ -157,7 +157,7 @@ public class SnapshotRepo : GLib.Object{ } // properties - + public string timeshift_path { owned get{ if (btrfs_mode){ @@ -168,13 +168,13 @@ public class SnapshotRepo : GLib.Object{ } } } - + public string snapshots_path { owned get{ return path_combine(timeshift_path, "snapshots"); } } - + // load --------------------------------------- public bool unlock_and_mount_devices(){ @@ -189,7 +189,7 @@ public class SnapshotRepo : GLib.Object{ } mount_path = unlock_and_mount_device(device, "/run/timeshift/backup"); - + if (mount_path.length == 0){ return false; } @@ -197,28 +197,28 @@ public class SnapshotRepo : GLib.Object{ // rsync mount_paths["@"] = ""; mount_paths["@home"] = ""; - + if (btrfs_mode){ - + mount_paths["@"] = mount_path; mount_paths["@home"] = mount_path; //default device_home = device; //default - + // mount @home if on different disk ------- - + var repo_subvolumes = Subvolume.detect_subvolumes_for_system_by_path(path_combine(mount_path,"@"), this, parent_window); - + if (repo_subvolumes.has_key("@home")){ - + var subvol = repo_subvolumes["@home"]; - + if (subvol.device_uuid != device.uuid){ - + // @home is on a separate device device_home = subvol.get_device(); - + mount_paths["@home"] = unlock_and_mount_device(device_home, "/run/timeshift/backup-home"); - + if (mount_paths["@home"].length == 0){ return false; } @@ -229,31 +229,31 @@ public class SnapshotRepo : GLib.Object{ load_snapshots(); log_debug("SnapshotRepo: unlock_and_mount_device(): exit"); - + return true; } public string unlock_and_mount_device(Device device_to_mount, string path_to_mount){ // mounts the device and returns mount path - + log_debug("SnapshotRepo: unlock_and_mount_device()"); Device dev = device_to_mount; - + if (dev == null){ log_debug("device=null"); } else{ log_debug("device=%s".printf(dev.device)); } - + // unlock encrypted device if (dev.is_encrypted_partition()){ dev = unlock_encrypted_device(dev); device = dev; // set repo device to unlocked child disk - + if (dev == null){ log_debug("device is null"); log_debug("SnapshotRepo: unlock_and_mount_device(): exit"); @@ -263,7 +263,7 @@ public class SnapshotRepo : GLib.Object{ // mount bool ok = Device.mount(dev.uuid, path_to_mount, ""); // TODO: check if already mounted - + if (ok){ return path_to_mount; } @@ -275,7 +275,7 @@ public class SnapshotRepo : GLib.Object{ public Device? unlock_encrypted_device(Device luks_device){ log_debug("SnapshotRepo: unlock_encrypted_device()"); - + if (luks_device == null){ log_debug("luks_device=null"); return null; @@ -290,14 +290,14 @@ public class SnapshotRepo : GLib.Object{ return luks_unlocked; } - + public bool load_snapshots(){ log_debug("SnapshotRepo: load_snapshots()"); - + snapshots.clear(); invalid_snapshots.clear(); - + if ((device == null) || !dir_exists(snapshots_path)){ return false; } @@ -310,9 +310,9 @@ public class SnapshotRepo : GLib.Object{ while (info != null) { if (info.get_file_type() == FileType.DIRECTORY) { if (info.get_name() != ".sync") { - + //log_debug("load_snapshots():" + snapshots_path + "/" + info.get_name()); - + Snapshot bak = new Snapshot(snapshots_path + "/" + info.get_name(), btrfs_mode, this); if (bak.valid){ snapshots.add(bak); @@ -337,7 +337,7 @@ public class SnapshotRepo : GLib.Object{ }); // reset the 'live' flag ------------ - + DateTime dt_boot = new DateTime.now_local(); dt_boot = dt_boot.add_seconds(-1.0 * get_system_uptime_seconds()); foreach(var bak in snapshots){ @@ -363,16 +363,16 @@ public class SnapshotRepo : GLib.Object{ if (btrfs_mode){ App.query_subvolume_info(this); } - + log_debug("loading snapshots from '%s': %d found".printf(snapshots_path, snapshots.size)); return true; } // get tagged snapshots ---------------------------------- - + public Gee.ArrayList get_snapshots_by_tag(string tag = ""){ - + var list = new Gee.ArrayList(); foreach(Snapshot bak in snapshots){ @@ -390,9 +390,9 @@ public class SnapshotRepo : GLib.Object{ } public Snapshot? get_latest_snapshot(string tag, string sys_uuid){ - + var list = get_snapshots_by_tag(tag); - + for(int i = list.size - 1; i >= 0; i--){ var bak = list[i]; if (bak.sys_uuid == sys_uuid){ @@ -404,7 +404,7 @@ public class SnapshotRepo : GLib.Object{ } public Snapshot? get_oldest_snapshot(string tag, string sys_uuid){ - + var list = get_snapshots_by_tag(tag); for(int i = 0; i < list.size; i++){ @@ -413,7 +413,7 @@ public class SnapshotRepo : GLib.Object{ return bak; } } - + return null; } @@ -422,7 +422,7 @@ public class SnapshotRepo : GLib.Object{ public void check_status(){ log_debug("SnapshotRepo: check_status()"); - + status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE; status_message = ""; status_details = ""; @@ -437,17 +437,17 @@ public class SnapshotRepo : GLib.Object{ } if ((App != null) && (App.app_mode.length == 0)){ - + log_debug("%s: '%s'".printf( _("Snapshot device"), (device == null) ? " UNKNOWN" : device.device)); - + log_debug("%s: %s".printf( _("Snapshot location"), mount_path)); log_debug(status_message); log_debug(status_details); - + log_debug("%s: %s".printf( _("Status"), status_code.to_string().replace("SNAPSHOT_LOCATION_STATUS_",""))); @@ -461,11 +461,11 @@ public class SnapshotRepo : GLib.Object{ public bool available(){ log_debug("SnapshotRepo: available()"); - + /*if (use_snapshot_path_custom){ log_debug("checking selected path"); - + if (snapshot_path_user.strip().length == 0){ status_message = _("Snapshot device not selected"); status_details = _("Select the snapshot device"); @@ -473,13 +473,13 @@ public class SnapshotRepo : GLib.Object{ return false; } else{ - + log_debug("path: %s".printf(snapshot_path_user)); - + if (!dir_exists(snapshot_path_user)){ log_debug("path not found"); - + status_message = _("Snapshot location not available"); status_details = _("Path not found") + ": '%s'".printf(snapshot_path_user); status_code = SnapshotLocationStatus.NOT_AVAILABLE; @@ -487,7 +487,7 @@ public class SnapshotRepo : GLib.Object{ } else{ log_debug("path exists"); - + bool is_readonly; bool hardlink_supported = filesystem_supports_hardlinks(snapshot_path_user, out is_readonly); @@ -515,7 +515,7 @@ public class SnapshotRepo : GLib.Object{ } } else{*/ - + //log_debug("checking selected device"); if (device == null){ @@ -553,7 +553,7 @@ public class SnapshotRepo : GLib.Object{ } public bool has_btrfs_system(){ - + log_debug("SnapshotRepo: has_btrfs_system()"); var root_path = path_combine(mount_paths["@"],"@"); @@ -571,11 +571,11 @@ public class SnapshotRepo : GLib.Object{ return true; } - + public bool has_snapshots(){ - + log_debug("SnapshotRepo: has_snapshots()"); - + //load_snapshots(); return (snapshots.size > 0); } @@ -583,7 +583,7 @@ public class SnapshotRepo : GLib.Object{ public bool has_space(){ log_debug("SnapshotRepo: has_space()"); - + if ((device != null) && (device.device.length > 0)){ device.query_disk_space(); } @@ -591,28 +591,28 @@ public class SnapshotRepo : GLib.Object{ log_debug("device is NULL"); return false; } - + if (snapshots.size > 0){ // has snapshots, check minimum space //log_debug("has snapshots"); - + if (device.free_bytes < Main.MIN_FREE_SPACE){ status_message = _("Not enough disk space"); status_message += " (< %s)".printf(format_file_size(Main.MIN_FREE_SPACE, false, "", true, 0)); - + status_details = _("Select another device or free up some space"); - + status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE; return false; } else{ //ok status_message = _("OK"); - + status_details = _("%d snapshots, %s free").printf( snapshots.size, format_file_size(device.free_bytes)); - + status_code = SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE; return true; } @@ -621,24 +621,24 @@ public class SnapshotRepo : GLib.Object{ // no snapshots, check estimated space log_debug("no snapshots"); - + var required_space = Main.first_snapshot_size; if (device.free_bytes < required_space){ status_message = _("Not enough disk space"); status_message += " (< %s)".printf(format_file_size(required_space)); - + status_details = _("Select another device or free up some space"); - + status_code = SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE; return false; } else{ status_message = _("No snapshots on this device"); - + status_details = _("First snapshot requires:"); status_details += " %s".printf(format_file_size(required_space)); - + status_code = SnapshotLocationStatus.NO_SNAPSHOTS_HAS_SPACE; return true; } @@ -646,11 +646,11 @@ public class SnapshotRepo : GLib.Object{ } public void print_status(){ - + check_status(); - + //log_msg(""); - + if (device == null){ log_msg("%-6s : %s".printf(_("Device"), _("Not Selected"))); } @@ -665,17 +665,17 @@ public class SnapshotRepo : GLib.Object{ log_msg(""); } - + // actions ------------------------------------- public void auto_remove(){ log_debug("SnapshotRepo: auto_remove()"); - + DateTime now = new DateTime.now_local(); DateTime dt_limit; int count_limit; - + // remove tags from older backups - boot --------------- var list = get_snapshots_by_tag("boot"); @@ -694,7 +694,7 @@ public class SnapshotRepo : GLib.Object{ string[] levels = { "hourly","daily","weekly","monthly" }; foreach(string level in levels){ - + list = get_snapshots_by_tag(level); if (list.size == 0) { continue; } @@ -727,16 +727,16 @@ public class SnapshotRepo : GLib.Object{ log_msg(_("Maximum backups exceeded for backup level") + " '%s'".printf(level)); int snaps_count = list.size; - + foreach(var snap in list){ if (snap.description.strip().length > 0){ continue; } // don't delete snapshots with comments - + if ((snap.date.compare(dt_limit) < 0) && (snaps_count > count_limit)){ snap.remove_tag(level); snaps_count--; - + log_msg(_("Snapshot") + " '%s' ".printf(list[0].name) + _("un-tagged") + " '%s'".printf(level)); } } @@ -765,7 +765,7 @@ public class SnapshotRepo : GLib.Object{ }*/ // delete untagged snapshots - + remove_untagged(); // delete older backups - minimum space ------- @@ -776,9 +776,9 @@ public class SnapshotRepo : GLib.Object{ show_msg = true; count = 0; while ((device.size_bytes - device.used_bytes) < App.minimum_free_disk_space){ - + load_snapshots(); - + if (snapshots.size > 0){ if (!snapshots[0].has_tag("ondemand")){ @@ -792,7 +792,7 @@ public class SnapshotRepo : GLib.Object{ snapshots[0].remove(); } } - + device.query_disk_space(); } * */ @@ -809,7 +809,7 @@ public class SnapshotRepo : GLib.Object{ public void remove_untagged(){ log_debug("SnapshotRepo: remove_untagged()"); - + bool show_msg = true; foreach(Snapshot bak in snapshots){ @@ -830,22 +830,22 @@ public class SnapshotRepo : GLib.Object{ public void remove_marked_for_deletion(){ bool show_msg = true; - + foreach(var bak in snapshots){ if (bak.marked_for_deletion){ - + if (show_msg){ log_msg("%s (%s):".printf(_("Removing snapshots"), _("marked for deletion"))); show_msg = false; } - + bak.remove(true); } } - + load_snapshots(); // update the list } - + public void remove_invalid(){ bool show_msg = true; @@ -856,10 +856,10 @@ public class SnapshotRepo : GLib.Object{ log_msg("%s (%s):".printf(_("Removing snapshots"), _("incomplete"))); show_msg = false; } - + bak.remove(true); } - + load_snapshots(); // update the list } @@ -868,7 +868,7 @@ public class SnapshotRepo : GLib.Object{ if (dir_exists(timeshift_path)){ log_msg(_("Removing snapshots") + " > " + _("all") + "..."); - + //delete snapshots foreach(var bak in snapshots){ bak.remove(true); @@ -879,7 +879,7 @@ public class SnapshotRepo : GLib.Object{ bool ok = delete_directory(timeshift_path); load_snapshots(); // update the list - + return ok; } else{ @@ -890,14 +890,14 @@ public class SnapshotRepo : GLib.Object{ public bool remove_sync_dir(){ string sync_dir = mount_path + "/timeshift/snapshots/.sync"; - + //delete .sync if (dir_exists(sync_dir)){ if (!delete_directory(sync_dir)){ return false; } } - + return true; } @@ -909,12 +909,12 @@ public class SnapshotRepo : GLib.Object{ return false; } } - + return true; } // private ------------------------------------------- - + private bool delete_directory(string dir_path){ thr_args1 = dir_path; @@ -981,7 +981,7 @@ public class SnapshotRepo : GLib.Object{ } // symlinks ---------------------------------------- - + public void create_symlinks(){ string cmd = ""; string std_out; @@ -999,7 +999,7 @@ public class SnapshotRepo : GLib.Object{ foreach(var bak in snapshots){ foreach(string tag in bak.tags){ - + path = "%s-%s".printf(snapshots_path, tag); cmd = "ln --symbolic \"../snapshots/%s\" -t \"%s\"".printf(bak.name, path); diff --git a/src/Core/Subvolume.vala b/src/Core/Subvolume.vala index 7712134..edf0fa0 100755 --- a/src/Core/Subvolume.vala +++ b/src/Core/Subvolume.vala @@ -42,9 +42,9 @@ public class Subvolume : GLib.Object{ //parent public SnapshotRepo? repo; - + public Subvolume(string name, string path, string parent_dev_uuid, SnapshotRepo? parent_repo){ - + this.name = name; this.path = path; this.device_uuid = parent_dev_uuid; @@ -68,10 +68,10 @@ public class Subvolume : GLib.Object{ } public Device? get_device(){ - + return Device.get_device_by_uuid(device_uuid); } - + public bool exists_on_disk{ get { return dir_exists(path); @@ -83,29 +83,29 @@ public class Subvolume : GLib.Object{ return (repo == null); } } - + public static Gee.HashMap detect_subvolumes_for_system_by_path( string system_path, SnapshotRepo? repo, Gtk.Window? parent_window){ var map = new Gee.HashMap(); - + log_debug("Searching subvolume for system at path: %s".printf(system_path)); - + var fstab = FsTabEntry.read_file(path_combine(system_path, "/etc/fstab")); var crypttab = CryptTabEntry.read_file(path_combine(system_path, "/etc/crypttab")); - + foreach(var item in fstab){ - + if (!item.is_for_system_directory()){ continue; } - + if (item.subvolume_name().length > 0){ - + var dev = item.resolve_device(crypttab, parent_window); var dev_name = (dev == null) ? "" : dev.device; var dev_uuid = (dev == null) ? "" : dev.uuid; - + log_debug("Found subvolume: %s, on device: %s".printf(item.subvolume_name(), dev_name)); - + var subvol = new Subvolume(item.subvolume_name(), item.mount_point, dev_uuid, repo); map.set(subvol.name, subvol); } @@ -115,12 +115,12 @@ public class Subvolume : GLib.Object{ } public void print_info(){ - + log_debug("name=%s, uuid=%s, id=%ld, path=%s".printf(name, device_uuid, id, path)); } // actions ---------------------------------- - + public bool remove(){ if (is_system_subvolume){ @@ -131,7 +131,7 @@ public class Subvolume : GLib.Object{ path = path_combine("/run/timeshift/backup-home", "@home"); } } - + string cmd = ""; string std_out, std_err, subpath; int ret_val; @@ -141,7 +141,7 @@ public class Subvolume : GLib.Object{ log_msg("%s: %s (Id:%ld)".printf(_("Deleting subvolume"), name, id)); string options = App.use_option_raw ? "--commit-after" : ""; - + subpath = path_combine(path, name); if (dir_exists(subpath)) { // there is a nested subvol to remove first cmd = "btrfs subvolume delete %s '%s'".printf(options, subpath); @@ -154,7 +154,7 @@ public class Subvolume : GLib.Object{ return false; } } - + cmd = "btrfs subvolume delete %s '%s'".printf(options, path); log_debug(cmd); ret_val = exec_sync(cmd, out std_out, out std_err); @@ -165,11 +165,11 @@ public class Subvolume : GLib.Object{ } log_msg("%s: %s (Id:%ld)\n".printf(_("Deleted subvolume"), name, id)); - + if ((id > 0) && (repo != null)){ log_msg("%s: 0/%ld".printf(_("Destroying qgroup"), id)); - + cmd = "btrfs qgroup destroy 0/%ld '%s'".printf(id, repo.mount_paths[name]); log_debug(cmd); ret_val = exec_sync(cmd, out std_out, out std_err); @@ -189,7 +189,7 @@ public class Subvolume : GLib.Object{ if (is_system_subvolume) { return false; } // restore snapshot subvolume by creating new subvolume snapshots ---------------------- - + string src_path = path; string dst_path = path_combine(mount_path, name); @@ -202,13 +202,13 @@ public class Subvolume : GLib.Object{ log_error("%s: %s".printf(_("Subvolume exists at destination"), dst_path)); return false; } - + string cmd = "btrfs subvolume snapshot '%s' '%s'".printf(src_path, dst_path); log_debug(cmd); string std_out, std_err; int status = exec_sync(cmd, out std_out, out std_err); - + if (status != 0){ log_error(std_err); log_error(_("btrfs returned an error") + ": %d".printf(status)); @@ -217,7 +217,7 @@ public class Subvolume : GLib.Object{ } log_msg(_("Restored system subvolume") + ": %s".printf(name)); - + return true; } } diff --git a/src/Gtk/AppGtk.vala b/src/Gtk/AppGtk.vala index fdcf730..c292b3d 100644 --- a/src/Gtk/AppGtk.vala +++ b/src/Gtk/AppGtk.vala @@ -49,7 +49,7 @@ extern void exit(int exit_code); public class AppGtk : GLib.Object { public static int main (string[] args) { - + set_locale(); Gtk.init(ref args); @@ -71,7 +71,7 @@ public class AppGtk : GLib.Object { } private static void set_locale() { - + log_debug("setting locale..."); Intl.setlocale(GLib.LocaleCategory.MESSAGES, "timeshift"); Intl.textdomain(GETTEXT_PACKAGE); @@ -80,7 +80,7 @@ public class AppGtk : GLib.Object { } public static bool parse_arguments(string[] args) { - + //parse options for (int k = 1; k < args.length; k++) // Oth arg is app path { @@ -107,7 +107,7 @@ public class AppGtk : GLib.Object { } public static string help_message() { - + string msg = "\n%s v%s by Tony George (%s)\n".printf(AppName, AppVersion, AppAuthorEmail); msg += "\n"; msg += _("Syntax") + ": timeshift-gtk [options]\n"; @@ -122,9 +122,9 @@ public class AppGtk : GLib.Object { } public static void check_if_admin(){ - + if (!user_is_admin()){ - + var msg = _("Admin access is required to backup and restore system files.") + "\n"; msg += _("Please re-run the application as admin (using 'sudo' or 'su')"); @@ -138,7 +138,7 @@ public class AppGtk : GLib.Object { } public static void start_application(){ - + // show main window var window = new MainWindow (); window.destroy.connect(Gtk.main_quit); diff --git a/src/Gtk/BackupBox.vala b/src/Gtk/BackupBox.vala index cf11af3..4926503 100755 --- a/src/Gtk/BackupBox.vala +++ b/src/Gtk/BackupBox.vala @@ -37,7 +37,7 @@ using TeeJee.System; using TeeJee.Misc; class BackupBox : Gtk.Box{ - + private Gtk.Spinner spinner; public Gtk.Label lbl_msg; public Gtk.Label lbl_status; @@ -62,25 +62,25 @@ class BackupBox : Gtk.Box{ public BackupBox (Gtk.Window _parent_window) { log_debug("BackupBox: BackupBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; - + add_label_header(this, _("Creating Snapshot..."), true); add_progress_area(); // add count labels --------------------------------- - + Gtk.SizeGroup sg_label = null; Gtk.SizeGroup sg_value = null; var label = add_label(this, _("File and directory counts:"), true); label.margin_bottom = 6; label.margin_top = 12; - + lbl_unchanged = add_count_label(this, _("No Change"), ref sg_label, ref sg_value); lbl_created = add_count_label(this, _("Created"), ref sg_label, ref sg_value); lbl_deleted = add_count_label(this, _("Deleted"), ref sg_label, ref sg_value); @@ -88,7 +88,7 @@ class BackupBox : Gtk.Box{ label = add_label(this, _("Changed items:"), true); label.margin_bottom = 6; - + lbl_checksum = add_count_label(this, _("Checksum"), ref sg_label, ref sg_value); lbl_size = add_count_label(this, _("Size"), ref sg_label, ref sg_value); lbl_timestamp = add_count_label(this, _("Timestamp"), ref sg_label, ref sg_value); @@ -102,14 +102,14 @@ class BackupBox : Gtk.Box{ } private void add_progress_area(){ - + var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6); add (hbox_status); - + spinner = new Gtk.Spinner(); spinner.active = true; hbox_status.add(spinner); - + //lbl_msg lbl_msg = add_label(hbox_status, _("Preparing...")); lbl_msg.hexpand = true; @@ -128,11 +128,11 @@ class BackupBox : Gtk.Box{ lbl_status.max_width_chars = 45; lbl_status.margin_bottom = 6; } - + private Gtk.Label add_count_label(Gtk.Box box, string text, ref Gtk.SizeGroup? sg_label, ref Gtk.SizeGroup? sg_value, int add_margin_bottom = 0){ - + var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6); box.add (hbox); @@ -141,7 +141,7 @@ class BackupBox : Gtk.Box{ label.margin_left = 12; label.margin_right = 6; var text_label = label; - + if (add_margin_bottom > 0){ label.margin_bottom = add_margin_bottom; } @@ -184,9 +184,9 @@ class BackupBox : Gtk.Box{ } if (App.btrfs_mode){ - + while (thread_is_running){ - + gtk_do_events(); sleep(200); @@ -200,7 +200,7 @@ class BackupBox : Gtk.Box{ #endif } else{ - + //string last_message = ""; int wait_interval_millis = 100; int status_line_counter = 0; @@ -208,7 +208,7 @@ class BackupBox : Gtk.Box{ string status_line = ""; string last_status_line = ""; int remaining_counter = 10; - + while (thread_is_running){ status_line = escape_html(App.task.status_line); @@ -234,8 +234,8 @@ class BackupBox : Gtk.Box{ App.task.stat_time_remaining + " " + _("remaining"); remaining_counter = 10; - } - + } + if (fraction < 0.99){ progressbar.fraction = fraction; #if XAPP @@ -271,9 +271,9 @@ class BackupBox : Gtk.Box{ //TODO: low: check if snapshot was created successfully. } - + private void take_snapshot_thread(){ - + thread_status_success = App.create_snapshot(true,parent_window); thread_is_running = false; } diff --git a/src/Gtk/BackupDeviceBox.vala b/src/Gtk/BackupDeviceBox.vala index 1e6a3a2..2530c67 100644 --- a/src/Gtk/BackupDeviceBox.vala +++ b/src/Gtk/BackupDeviceBox.vala @@ -38,13 +38,13 @@ class BackupDeviceBox : Gtk.Box{ private Gtk.InfoBar infobar_location; private Gtk.Label lbl_infobar_location; private Gtk.Label lbl_common; - + private Gtk.Window parent_window; public BackupDeviceBox (Gtk.Window _parent_window) { log_debug("BackupDeviceBox: BackupDeviceBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -58,9 +58,9 @@ class BackupDeviceBox : Gtk.Box{ // buffer var label = add_label(hbox, ""); label.hexpand = true; - + // refresh device button - + var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); var btn_refresh = add_button(hbox, _("Refresh"), "", size_group, null); btn_refresh.clicked.connect(()=>{ @@ -69,7 +69,7 @@ class BackupDeviceBox : Gtk.Box{ }); // TODO: show this message somewhere - + //var msg = _("Only Linux partitions are supported."); //msg += "\n" + _("Snapshots will be saved in folder /timeshift"); @@ -86,13 +86,13 @@ class BackupDeviceBox : Gtk.Box{ } public void refresh(){ - + tv_devices_refresh(); - + check_backup_location(); if (App.btrfs_mode){ - + lbl_common.label = "• %s\n• %s\n• %s".printf( _("Devices displayed above have BTRFS file systems."), _("BTRFS snapshots are saved on system partition. Other partitions are not supported."), @@ -110,16 +110,16 @@ class BackupDeviceBox : Gtk.Box{ } private void init_tv_devices(){ - + tv_devices = add_treeview(this); tv_devices.vexpand = true; tv_devices.headers_clickable = true; //tv_devices.rules_hint = true; tv_devices.activate_on_single_click = true; //tv_devices.headers_clickable = true; - + // device name - + Gtk.CellRendererPixbuf cell_pix; Gtk.CellRendererToggle cell_radio; Gtk.CellRendererText cell_text; @@ -128,13 +128,13 @@ class BackupDeviceBox : Gtk.Box{ out cell_pix, out cell_radio, out cell_text); col.resizable = true; - + col.set_cell_data_func(cell_pix, (cell_layout, cell, model, iter)=>{ Device dev; model.get (iter, 0, out dev, -1); (cell as Gtk.CellRendererPixbuf).visible = (dev.type == "disk"); - + }); col.add_attribute(cell_pix, "icon-name", 2); @@ -184,9 +184,9 @@ class BackupDeviceBox : Gtk.Box{ //(cell as Gtk.CellRendererText).sensitive = (dev.type != "disk"); }); - + // type - + col = add_column_text(tv_devices, _("Type"), out cell_text); col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ @@ -198,10 +198,10 @@ class BackupDeviceBox : Gtk.Box{ }); // size - + col = add_column_text(tv_devices, _("Size"), out cell_text); cell_text.xalign = (float) 1.0; - + col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ Device dev; model.get (iter, 0, out dev, -1); @@ -211,10 +211,10 @@ class BackupDeviceBox : Gtk.Box{ }); // free - + col = add_column_text(tv_devices, _("Free"), out cell_text); cell_text.xalign = (float) 1.0; - + col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ Device dev; model.get (iter, 0, out dev, -1); @@ -231,10 +231,10 @@ class BackupDeviceBox : Gtk.Box{ }); // name - + col = add_column_text(tv_devices, _("Name"), out cell_text); cell_text.xalign = 0.0f; - + col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ Device dev; model.get (iter, 0, out dev, -1); @@ -250,10 +250,10 @@ class BackupDeviceBox : Gtk.Box{ }); // label - + col = add_column_text(tv_devices, _("Label"), out cell_text); cell_text.xalign = 0.0f; - + col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ Device dev; model.get (iter, 0, out dev, -1); @@ -267,14 +267,14 @@ class BackupDeviceBox : Gtk.Box{ (cell as Gtk.CellRendererText).sensitive = (dev.type != "disk"); }); - + // buffer col = add_column_text(tv_devices, "", out cell_text); col.expand = true; - + /*// label - + col = add_column_text(tv_devices, _("Label"), out cell_text); col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ @@ -285,8 +285,8 @@ class BackupDeviceBox : Gtk.Box{ (cell as Gtk.CellRendererText).sensitive = (dev.type != "disk"); });*/ - - + + // events tv_devices.row_activated.connect((path, column) => { @@ -308,7 +308,7 @@ class BackupDeviceBox : Gtk.Box{ store.foreach((model, path, iter) => { Device dev; store.get (iter, 0, out dev); - + if ((App.repo.device != null) && (App.repo.device.uuid == dev.uuid)){ store.set (iter, 3, true); //tv_devices.get_selection().select_iter(iter); @@ -323,12 +323,12 @@ class BackupDeviceBox : Gtk.Box{ } private void init_infobar_location(){ - + var infobar = new Gtk.InfoBar(); infobar.no_show_all = true; add(infobar); infobar_location = infobar; - + var content = (Gtk.Box) infobar.get_content_area(); var label = add_label(content, ""); lbl_infobar_location = label; @@ -340,7 +340,7 @@ class BackupDeviceBox : Gtk.Box{ scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER; scrolled.set_size_request(-1, 100); this.add(scrolled); - + label = new Gtk.Label(""); label.set_use_markup(true); label.xalign = (float) 0.0; @@ -354,13 +354,13 @@ class BackupDeviceBox : Gtk.Box{ private void try_change_device(Device dev){ log_debug("try_change_device: %s".printf(dev.device)); - + if (dev.type == "disk"){ bool found_child = false; if ((App.btrfs_mode && (dev.fstype == "btrfs")) || (!App.btrfs_mode && dev.has_linux_filesystem())){ - + change_backup_device(dev); found_child = true; } @@ -368,26 +368,26 @@ class BackupDeviceBox : Gtk.Box{ if (!found_child){ // find first valid partition - + foreach (var child in dev.children){ - + if ((App.btrfs_mode && (child.fstype == "btrfs")) || (!App.btrfs_mode && child.has_linux_filesystem())){ - + change_backup_device(child); found_child = true; break; } } } - + if (!found_child){ - + string msg = _("Selected device does not have Linux partition"); - + if (App.btrfs_mode){ msg = _("Selected device does not have BTRFS partition"); } - + lbl_infobar_location.label = "%s".printf(msg); infobar_location.message_type = Gtk.MessageType.ERROR; infobar_location.no_show_all = false; @@ -395,17 +395,17 @@ class BackupDeviceBox : Gtk.Box{ } } else if (dev.has_children()){ - + // select the child instead of parent change_backup_device(dev.children[0]); } else if (!dev.has_children()){ - + // select the device change_backup_device(dev); } else { - + // ask user to select lbl_infobar_location.label = "%s".printf(_("Select a partition on this disk")); infobar_location.message_type = Gtk.MessageType.ERROR; @@ -415,7 +415,7 @@ class BackupDeviceBox : Gtk.Box{ } private void change_backup_device(Device pi){ - + // return if device has not changed if ((App.repo.device != null) && (pi.uuid == App.repo.device.uuid)){ return; } @@ -428,20 +428,20 @@ class BackupDeviceBox : Gtk.Box{ App.repo = new SnapshotRepo.from_device(pi, parent_window, App.btrfs_mode); if (pi.fstype == "luks"){ - + App.update_partitions(); var dev = Device.find_device_in_list(App.partitions, pi.uuid); - + if (dev.has_children()){ - + log_debug("has children"); - + if (dev.children[0].has_linux_filesystem()){ - + log_debug("has linux filesystem: %s".printf(dev.children[0].fstype)); log_msg("selecting child device: %s".printf(dev.children[0].device)); - + App.repo = new SnapshotRepo.from_device(dev.children[0], parent_window, App.btrfs_mode); tv_devices_refresh(); } @@ -457,21 +457,21 @@ class BackupDeviceBox : Gtk.Box{ } private bool check_backup_location(){ - + bool ok = true; App.repo.check_status(); string message = App.repo.status_message; string details = App.repo.status_details; int status_code = App.repo.status_code; - + // TODO: call check on repo directly - + message = escape_html(message); details = escape_html(details); - + if (App.live_system()){ - + switch (status_code){ case SnapshotLocationStatus.NOT_SELECTED: lbl_infobar_location.label = "%s".printf(details); @@ -480,7 +480,7 @@ class BackupDeviceBox : Gtk.Box{ infobar_location.show_all(); ok = false; break; - + case SnapshotLocationStatus.NOT_AVAILABLE: lbl_infobar_location.label = "%s".printf(message); infobar_location.message_type = Gtk.MessageType.ERROR; @@ -531,7 +531,7 @@ class BackupDeviceBox : Gtk.Box{ infobar_location.show_all(); ok = false; break; - + case SnapshotLocationStatus.NOT_AVAILABLE: case SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE: case SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE: @@ -568,12 +568,12 @@ class BackupDeviceBox : Gtk.Box{ } } - + return ok; } private void tv_devices_refresh(){ - + App.update_partitions(); var model = new Gtk.TreeStore(4, @@ -581,13 +581,13 @@ class BackupDeviceBox : Gtk.Box{ typeof(string), typeof(string), typeof(bool)); - + tv_devices.set_model (model); TreeIter iter0; foreach(var disk in App.partitions) { - + if (disk.type != "disk") { continue; } model.append(out iter0, null); @@ -624,15 +624,15 @@ class BackupDeviceBox : Gtk.Box{ continue; } } - + if (part.pkname == parent.kname) { - + TreeIter iter1; model.append(out iter1, iter0); model.set(iter1, 0, part, -1); model.set(iter1, 1, part.tooltip_text(), -1); model.set(iter1, 2, (part.fstype == "luks") ? "locked" : IconManager.ICON_HARDDRIVE, -1); - + if (parent.fstype == "luks"){ // change parent's icon to unlocked model.set(iter0, 2, "unlocked", -1); @@ -649,7 +649,7 @@ class BackupDeviceBox : Gtk.Box{ } else if ((part.kname == parent.kname) && (part.type == "disk") && part.has_linux_filesystem() && !part.has_children()){ - + // partition-less disk with linux filesystem // create a dummy partition @@ -664,7 +664,7 @@ class BackupDeviceBox : Gtk.Box{ model.set(iter1, 0, part2, -1); model.set(iter1, 1, part2.tooltip_text(), -1); model.set(iter1, 2, (part2.fstype == "luks") ? "locked" : IconManager.ICON_HARDDRIVE, -1); - + if ((App.repo.device != null) && (part2.uuid == App.repo.device.uuid)){ model.set(iter1, 3, true, -1); } diff --git a/src/Gtk/BackupFinishBox.vala b/src/Gtk/BackupFinishBox.vala index 45c9b31..0343be5 100644 --- a/src/Gtk/BackupFinishBox.vala +++ b/src/Gtk/BackupFinishBox.vala @@ -38,9 +38,9 @@ class BackupFinishBox : Gtk.Box{ private Gtk.Window parent_window; public BackupFinishBox (Gtk.Window _parent_window) { - + log_debug("BackupFinishBox: BackupFinishBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -56,7 +56,7 @@ class BackupFinishBox : Gtk.Box{ public void update_message(bool success){ var txt = ""; - + txt = _("Snapshot Created"); if (!success){ @@ -64,11 +64,11 @@ class BackupFinishBox : Gtk.Box{ } lbl_header.label = format_text(txt, true, false, true); - + var msg = ""; msg += _("Close window to exit") + "\n\n"; - + lbl_message.label = msg; } diff --git a/src/Gtk/BackupWindow.vala b/src/Gtk/BackupWindow.vala index a66c68a..ee4db68 100644 --- a/src/Gtk/BackupWindow.vala +++ b/src/Gtk/BackupWindow.vala @@ -33,11 +33,11 @@ using TeeJee.System; using TeeJee.Misc; class BackupWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.Notebook notebook; private Gtk.ButtonBox bbox_action; - + // tabs private EstimateBox estimate_box; private BackupDeviceBox backup_dev_box; @@ -58,7 +58,7 @@ class BackupWindow : Gtk.Window{ public BackupWindow() { log_debug("BackupWindow: BackupWindow()"); - + this.title = _("Create Snapshot"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -78,7 +78,7 @@ class BackupWindow : Gtk.Window{ notebook = add_notebook(vbox_main, false, false); Gtk.Label label; - + label = new Gtk.Label(_("Estimate")); estimate_box = new EstimateBox(this); estimate_box.margin = 12; @@ -107,7 +107,7 @@ class BackupWindow : Gtk.Window{ log_debug("BackupWindow: BackupWindow(): exit"); } - + private bool init_delayed(){ if (tmr_init > 0){ @@ -119,48 +119,48 @@ class BackupWindow : Gtk.Window{ return false; } - + private bool on_delete_event(Gdk.EventAny event){ save_changes(); - + return false; // close window } - + private void save_changes(){ - + App.cron_job_update(); } - + private void create_actions(){ - + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); vbox_main.add(hbox); - + var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); bbox.margin = 12; bbox.spacing = 6; bbox.hexpand = true; hbox.add(bbox); - + bbox_action = bbox; #if GTK3_18 - bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); + bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); #endif - + Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // previous - + btn_prev = add_button(bbox, _("Previous"), "", size_group, null); - + btn_prev.clicked.connect(()=>{ go_prev(); }); // next - + btn_next = add_button(bbox, _("Next"), "", size_group, null); btn_next.clicked.connect(()=>{ @@ -168,7 +168,7 @@ class BackupWindow : Gtk.Window{ }); // close - + btn_close = add_button(bbox, _("Close"), "", size_group, null); btn_close.clicked.connect(()=>{ @@ -177,14 +177,14 @@ class BackupWindow : Gtk.Window{ }); // cancel - + btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null); btn_cancel.clicked.connect(()=>{ if (App.task != null){ App.task.stop(AppStatus.CANCELLED); } - + this.destroy(); // TODO: Show error page }); @@ -192,18 +192,18 @@ class BackupWindow : Gtk.Window{ } private void action_buttons_set_no_show_all(bool val){ - + btn_prev.no_show_all = val; btn_next.no_show_all = val; btn_close.no_show_all = val; btn_cancel.no_show_all = val; } - + // navigation private void go_first(){ - + // set initial tab if (App.btrfs_mode){ @@ -223,9 +223,9 @@ class BackupWindow : Gtk.Window{ initialize_tab(); } - + private void go_prev(){ - + switch(notebook.page){ case Tabs.ESTIMATE: case Tabs.BACKUP_DEVICE: @@ -233,16 +233,16 @@ class BackupWindow : Gtk.Window{ // btn_previous is disabled for this page break; } - + initialize_tab(); } - + private void go_next(){ - + if (!validate_current_tab()){ return; } - + switch(notebook.page){ case Tabs.ESTIMATE: notebook.page = Tabs.BACKUP_DEVICE; @@ -257,7 +257,7 @@ class BackupWindow : Gtk.Window{ destroy(); break; } - + initialize_tab(); } @@ -271,7 +271,7 @@ class BackupWindow : Gtk.Window{ // show/hide actions ----------------------------------- action_buttons_set_no_show_all(false); - + switch(notebook.page){ case Tabs.ESTIMATE: case Tabs.BACKUP: @@ -320,16 +320,16 @@ class BackupWindow : Gtk.Window{ } } - + private bool validate_current_tab(){ - + if (notebook.page == Tabs.BACKUP_DEVICE){ if (!App.repo.available() || !App.repo.has_space()){ - + gtk_messagebox(App.repo.status_message, App.repo.status_details, this, true); - + return false; } } diff --git a/src/Gtk/BootOptionsBox.vala b/src/Gtk/BootOptionsBox.vala index 9b2d242..6e66372 100644 --- a/src/Gtk/BootOptionsBox.vala +++ b/src/Gtk/BootOptionsBox.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class BootOptionsBox : Gtk.Box{ - + private Gtk.Box option_box; private Gtk.ComboBox cmb_grub_dev; @@ -45,7 +45,7 @@ class BootOptionsBox : Gtk.Box{ public BootOptionsBox (Gtk.Window _parent_window) { log_debug("BootOptionsBox: BootOptionsBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -68,7 +68,7 @@ class BootOptionsBox : Gtk.Box{ //var label = add_label_header(this, _("Select Bootloader Options"), true); add_chk_reinstall_grub(); - + var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6); hbox.margin_left = 12; add (hbox); @@ -77,7 +77,7 @@ class BootOptionsBox : Gtk.Box{ cmb_grub_dev = new ComboBox (); cmb_grub_dev.hexpand = true; hbox.add(cmb_grub_dev); - + var cell_text = new CellRendererText (); cell_text.text = ""; cmb_grub_dev.pack_start(cell_text, false); @@ -107,14 +107,14 @@ class BootOptionsBox : Gtk.Box{ hbox = new Gtk.Box(Orientation.HORIZONTAL, 6); add (hbox); - + add_chk_update_initramfs(hbox); add_chk_update_grub(hbox); } private void add_chk_reinstall_grub(){ - + var chk = new CheckButton.with_label(_("(Re)install GRUB2 on:")); chk.active = false; chk.set_tooltip_markup(_("Re-installs the GRUB2 bootloader on the selected device.")); @@ -130,7 +130,7 @@ class BootOptionsBox : Gtk.Box{ } private void add_chk_update_initramfs(Gtk.Box hbox){ - + //chk_update_initramfs var chk = new CheckButton.with_label(_("Update initramfs")); chk.active = false; @@ -145,7 +145,7 @@ class BootOptionsBox : Gtk.Box{ } private void add_chk_update_grub(Gtk.Box hbox){ - + //chk_update_grub var chk = new CheckButton.with_label(_("Update GRUB menu")); chk.active = false; @@ -160,9 +160,9 @@ class BootOptionsBox : Gtk.Box{ } private void save_grub_device_selection(){ - + App.grub_device = ""; - + if (App.reinstall_grub2){ Device entry; TreeIter iter; @@ -177,16 +177,16 @@ class BootOptionsBox : Gtk.Box{ private void refresh_options(){ refresh_cmb_grub_dev(); - + chk_reinstall_grub.active = App.reinstall_grub2; cmb_grub_dev.sensitive = chk_reinstall_grub.active; chk_update_initramfs.active = App.update_initramfs; chk_update_grub.active = App.update_grub; - + chk_reinstall_grub.sensitive = true; chk_update_initramfs.sensitive = true; chk_update_grub.sensitive = true; - + if (App.mirror_system){ // bootloader must be re-installed chk_reinstall_grub.sensitive = false; @@ -200,14 +200,14 @@ class BootOptionsBox : Gtk.Box{ } } } - + private void refresh_cmb_grub_dev(){ - + var store = new Gtk.ListStore(2, typeof(Device), typeof(string)); TreeIter iter; foreach(Device dev in Device.get_block_devices_using_lsblk()) { - + // select disk and normal partitions, skip others (loop crypt rom lvm) if ((dev.type != "disk") && (dev.type != "part")){ continue; @@ -238,9 +238,9 @@ class BootOptionsBox : Gtk.Box{ if ((cmb_grub_dev == null) || (cmb_grub_dev.model == null)){ return; } - + log_debug("BootOptionsBox: cmb_grub_dev_select_default()"); - + if (App.grub_device.length == 0){ cmb_grub_dev.active = -1; return; @@ -250,14 +250,14 @@ class BootOptionsBox : Gtk.Box{ var store = (Gtk.ListStore) cmb_grub_dev.model; int index = -1; int active = -1; - + for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) { - + Device dev_iter; store.get(iter, 0, out dev_iter); - + index++; - + if (dev_iter.device == App.grub_device){ active = index; break; diff --git a/src/Gtk/BootOptionsWindow.vala b/src/Gtk/BootOptionsWindow.vala index 3242c4f..94d213c 100644 --- a/src/Gtk/BootOptionsWindow.vala +++ b/src/Gtk/BootOptionsWindow.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class BootOptionsWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.ButtonBox bbox_action; private BootOptionsBox boot_options_box; @@ -45,7 +45,7 @@ class BootOptionsWindow : Gtk.Window{ public BootOptionsWindow() { log_debug("BootOptionsWindow: BootOptionsWindow()"); - + this.title = _("Bootloader Options"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -62,7 +62,7 @@ class BootOptionsWindow : Gtk.Window{ boot_options_box = new BootOptionsBox(this); boot_options_box.margin = 0; vbox_main.add(boot_options_box); - + create_actions(); show_all(); @@ -81,31 +81,31 @@ class BootOptionsWindow : Gtk.Window{ return false; } - + private bool on_delete_event(Gdk.EventAny event){ //save_changes(); - + return false; // close window } - + private void save_changes(){ //App.cron_job_update(); } - + private void create_actions(){ - + var hbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); hbox.margin = 0; hbox.margin_top = 24; vbox_main.add(hbox); var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // close var btn_close = add_button(hbox, _("Close"), "", size_group, null); //hbox.set_child_packing(btn_close, false, true, 6, Gtk.PackType.END); - + btn_close.clicked.connect(()=>{ save_changes(); this.destroy(); diff --git a/src/Gtk/DeleteBox.vala b/src/Gtk/DeleteBox.vala index bb0f9b0..c824bbd 100644 --- a/src/Gtk/DeleteBox.vala +++ b/src/Gtk/DeleteBox.vala @@ -48,22 +48,22 @@ class DeleteBox : Gtk.Box{ public DeleteBox (Gtk.Window _parent_window) { log_debug("DeleteBox: DeleteBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; - + // header add_label_header(this, _("Deleting Snapshots..."), true); var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6); add (hbox_status); - + spinner = new Gtk.Spinner(); spinner.active = true; hbox_status.add(spinner); - + //lbl_msg lbl_msg = add_label(hbox_status, _("Preparing...")); lbl_msg.hexpand = true; @@ -97,9 +97,9 @@ class DeleteBox : Gtk.Box{ } if (App.btrfs_mode){ - + while (App.thread_delete_running){ - + lbl_msg.label = App.progress_text; gtk_do_events(); sleep(200); @@ -114,14 +114,14 @@ class DeleteBox : Gtk.Box{ #endif } else{ - + int wait_interval_millis = 100; int status_line_counter = 0; int status_line_counter_default = 1000 / wait_interval_millis; string status_line = ""; string last_status_line = ""; int remaining_counter = 10; - + while (App.thread_delete_running){ status_line = escape_html(App.delete_file_task.status_line); @@ -143,14 +143,14 @@ class DeleteBox : Gtk.Box{ // time remaining remaining_counter--; - + if (remaining_counter == 0){ - + lbl_remaining.label = App.delete_file_task.stat_time_remaining + " " + _("remaining"); remaining_counter = 10; } - + if (fraction < 0.99){ progressbar.fraction = fraction; @@ -170,7 +170,7 @@ class DeleteBox : Gtk.Box{ XApp.set_window_progress(parent_window, 0); #endif } - + //parent_window.destroy(); return App.thread_delete_success; diff --git a/src/Gtk/DeleteFinishBox.vala b/src/Gtk/DeleteFinishBox.vala index 2405fa4..db99034 100644 --- a/src/Gtk/DeleteFinishBox.vala +++ b/src/Gtk/DeleteFinishBox.vala @@ -38,9 +38,9 @@ class DeleteFinishBox : Gtk.Box{ private Gtk.Window parent_window; public DeleteFinishBox (Gtk.Window _parent_window) { - + log_debug("DeleteFinishBox: DeleteFinishBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -56,7 +56,7 @@ class DeleteFinishBox : Gtk.Box{ public void update_message(bool success){ var txt = ""; - + txt = _("Snapshot(s) Deleted"); if (!success){ @@ -64,12 +64,12 @@ class DeleteFinishBox : Gtk.Box{ } lbl_header.label = format_text(txt, true, false, true); - + var msg = ""; msg += "\n"; msg += "" + _("Close window to exit") + "\n\n"; - + lbl_message.label = msg; } diff --git a/src/Gtk/DeleteWindow.vala b/src/Gtk/DeleteWindow.vala index 3f4cc1d..6ae7cc9 100644 --- a/src/Gtk/DeleteWindow.vala +++ b/src/Gtk/DeleteWindow.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class DeleteWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.Notebook notebook; private Gtk.ButtonBox bbox_action; @@ -54,11 +54,11 @@ class DeleteWindow : Gtk.Window{ private int def_width = 500; private int def_height = 500; private bool success = false; - + public DeleteWindow() { log_debug("DeleteWindow: DeleteWindow()"); - + this.title = _("Delete Snapshots"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -68,7 +68,7 @@ class DeleteWindow : Gtk.Window{ this.delete_event.connect(on_delete_event); this.resize(def_width, def_height); - + // vbox_main vbox_main = new Gtk.Box(Orientation.VERTICAL, 6); vbox_main.margin = 0; @@ -78,23 +78,23 @@ class DeleteWindow : Gtk.Window{ notebook = add_notebook(vbox_main, false, false); // create tab - + var vbox_tab = new Gtk.Box(Orientation.VERTICAL, 6); vbox_tab.margin = 12; - + add_label_header(vbox_tab, _("Select Snapshots"), true); add_label(vbox_tab, _("Select the snapshots to be deleted")); - + var label = new Gtk.Label(_("Snapshots")); - + snapshot_list_box = new SnapshotListBox(this); snapshot_list_box.hide_context_menu(); snapshot_list_box.margin = 0; vbox_tab.add(snapshot_list_box); - + notebook.append_page (vbox_tab, label); - + label = new Gtk.Label(_("Delete")); delete_box = new DeleteBox(this); delete_box.margin = 12; @@ -115,7 +115,7 @@ class DeleteWindow : Gtk.Window{ log_debug("DeleteWindow: DeleteWindow(): exit"); } - + private bool init_delayed(){ if (tmr_init > 0){ @@ -132,36 +132,36 @@ class DeleteWindow : Gtk.Window{ return false; // close window } - + private void create_actions(){ - + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); vbox_main.add(hbox); - + var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); bbox.margin = 12; bbox.spacing = 6; bbox.hexpand = true; hbox.add(bbox); - + bbox_action = bbox; #if GTK3_18 - bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); + bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); #endif - + Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // previous - + btn_prev = add_button(bbox, _("Previous"), "", size_group, null); - + btn_prev.clicked.connect(()=>{ go_prev(); }); // next - + btn_next = add_button(bbox, _("Next"), "", size_group, null); btn_next.clicked.connect(()=>{ @@ -169,7 +169,7 @@ class DeleteWindow : Gtk.Window{ }); // close - + btn_close = add_button(bbox, _("Close"), "", size_group, null); btn_close.clicked.connect(()=>{ @@ -177,16 +177,16 @@ class DeleteWindow : Gtk.Window{ }); // hide - + btn_hide = add_button(bbox, _("Hide"), "", size_group, null); btn_hide.set_tooltip_text(_("Hide this window (files will be deleted in background)")); - + btn_hide.clicked.connect(()=>{ this.destroy(); }); - + // cancel - + btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null); btn_cancel.clicked.connect(()=>{ @@ -196,7 +196,7 @@ class DeleteWindow : Gtk.Window{ if (App.delete_file_task != null){ App.delete_file_task.stop(AppStatus.CANCELLED); } - + this.destroy(); // TODO: Show error page }); @@ -206,20 +206,20 @@ class DeleteWindow : Gtk.Window{ } private void action_buttons_set_no_show_all(bool val){ - + btn_prev.no_show_all = val; btn_next.no_show_all = val; btn_hide.no_show_all = val; btn_close.no_show_all = val; btn_cancel.no_show_all = val; } - + // navigation private void go_first(){ - + // set initial tab - + if ((App.delete_list.size == 0) && !App.thread_delete_running){ notebook.page = Tabs.SNAPSHOT_LIST; } @@ -229,40 +229,40 @@ class DeleteWindow : Gtk.Window{ initialize_tab(); } - + private void go_prev(){ - + switch(notebook.page){ case Tabs.SNAPSHOT_LIST: case Tabs.DELETE: // btn_previous is disabled for this page break; } - + initialize_tab(); } - + private void go_next(){ - + if (!validate_current_tab()){ return; } - + switch(notebook.page){ case Tabs.SNAPSHOT_LIST: App.delete_list = snapshot_list_box.selected_snapshots(); notebook.page = Tabs.DELETE; break; - + case Tabs.DELETE: notebook.page = Tabs.DELETE_FINISH; break; - + case Tabs.DELETE_FINISH: destroy(); break; } - + initialize_tab(); } @@ -278,7 +278,7 @@ class DeleteWindow : Gtk.Window{ // show/hide actions ----------------------------------- action_buttons_set_no_show_all(false); - + switch(notebook.page){ case Tabs.DELETE: btn_prev.hide(); @@ -287,7 +287,7 @@ class DeleteWindow : Gtk.Window{ btn_hide.show(); btn_cancel.show(); break; - + case Tabs.SNAPSHOT_LIST: btn_prev.show(); btn_next.show(); @@ -298,7 +298,7 @@ class DeleteWindow : Gtk.Window{ btn_next.sensitive = true; btn_close.sensitive = true; break; - + case Tabs.DELETE_FINISH: btn_prev.hide(); btn_next.hide(); @@ -326,7 +326,7 @@ class DeleteWindow : Gtk.Window{ } private bool validate_current_tab(){ - + switch(notebook.page){ case Tabs.SNAPSHOT_LIST: var sel = snapshot_list_box.treeview.get_selection (); @@ -340,7 +340,7 @@ class DeleteWindow : Gtk.Window{ else{ return true; } - + default: return true; } diff --git a/src/Gtk/EstimateBox.vala b/src/Gtk/EstimateBox.vala index 0a2ab9f..efdfaf7 100644 --- a/src/Gtk/EstimateBox.vala +++ b/src/Gtk/EstimateBox.vala @@ -37,31 +37,31 @@ using TeeJee.System; using TeeJee.Misc; class EstimateBox : Gtk.Box{ - + private Gtk.ProgressBar progressbar; private Gtk.Window parent_window; - + private bool thread_is_running = false; public EstimateBox (Gtk.Window _parent_window) { log_debug("EstimateBox: EstimateBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; - + // header add_label_header(this, _("Estimating System Size..."), true); var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6); add (hbox_status); - + var spinner = new Gtk.Spinner(); spinner.active = true; hbox_status.add(spinner); - + //lbl_msg var lbl_msg = add_label(hbox_status, _("Please wait...")); lbl_msg.halign = Align.START; @@ -83,14 +83,14 @@ class EstimateBox : Gtk.Box{ log_debug("EstimateBox: size > 0"); return; } - + progressbar.fraction = 0.0; // start the estimation if not already running if (!App.thread_estimate_running){ log_debug("EstimateBox: thread started"); - + try { thread_is_running = true; Thread.create (estimate_system_size_thread, true); @@ -103,16 +103,16 @@ class EstimateBox : Gtk.Box{ // wait for completion and increment progressbar while (thread_is_running){ - + if (progressbar.fraction < 98.0){ - + progressbar.fraction += 0.005; #if XAPP XApp.set_window_progress(parent_window, (int)(progressbar.fraction * 100.0)); #endif } - + gtk_do_events(); sleep(100); } @@ -123,7 +123,7 @@ class EstimateBox : Gtk.Box{ } private void estimate_system_size_thread(){ - + App.estimate_system_size(); log_debug("EstimateBox: thread finished"); thread_is_running = false; diff --git a/src/Gtk/ExcludeAppsBox.vala b/src/Gtk/ExcludeAppsBox.vala index 51e9450..2d26f74 100644 --- a/src/Gtk/ExcludeAppsBox.vala +++ b/src/Gtk/ExcludeAppsBox.vala @@ -39,7 +39,7 @@ class ExcludeAppsBox : Gtk.Box{ public ExcludeAppsBox (Gtk.Window _parent_window) { log_debug("ExcludeAppsBox: ExcludeAppsBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -47,7 +47,7 @@ class ExcludeAppsBox : Gtk.Box{ var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); add(box); - + add_label_header(box, _("Exclude Application Settings"), true); //add_label(this, _("Selected items will be excluded")); @@ -86,7 +86,7 @@ class ExcludeAppsBox : Gtk.Box{ var col = new TreeViewColumn(); col.expand = true; treeview.append_column(col); - + // margin var cell_text = new CellRendererText(); cell_text.text = ""; @@ -109,20 +109,20 @@ class ExcludeAppsBox : Gtk.Box{ Gtk.TreeIter iter; var store = (Gtk.ListStore) treeview.model; store.get_iter(out iter, tree_path); - + AppExcludeEntry entry; store.get(iter, 0, out entry); entry.enabled = !cell_toggle.active; - + store.set(iter, 1, !cell_toggle.active); }); // pattern cell_text = new CellRendererText (); col.pack_start (cell_text, false); - + col.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ - + AppExcludeEntry entry; model.get (iter, 0, out entry, -1); (cell as Gtk.CellRendererText).text = entry.name; @@ -130,23 +130,23 @@ class ExcludeAppsBox : Gtk.Box{ } private void init_exclude_summary_link(Gtk.Box box){ - + var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); var button = add_button(box, _("Summary"), "", size_group, null); button.clicked.connect(()=>{ new ExcludeListSummaryWindow(true); }); } - + // helpers public void refresh(){ - + refresh_treeview(); } - + public void refresh_treeview(){ - + var model = new Gtk.ListStore(3, typeof(AppExcludeEntry), typeof(bool), typeof(string)); treeview.model = model; diff --git a/src/Gtk/ExcludeBox.vala b/src/Gtk/ExcludeBox.vala index 4333e45..0cdddbf 100644 --- a/src/Gtk/ExcludeBox.vala +++ b/src/Gtk/ExcludeBox.vala @@ -33,16 +33,16 @@ using TeeJee.System; using TeeJee.Misc; class ExcludeBox : Gtk.Box{ - + private Gtk.TreeView treeview; private Gtk.Window parent_window; private UsersBox users_box; private Gtk.Label lbl_message; - + public ExcludeBox (Gtk.Window _parent_window) { log_debug("ExcludeBox: ExcludeBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -50,7 +50,7 @@ class ExcludeBox : Gtk.Box{ var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); add(box); - + add_label_header(box, _("Include / Exclude Patterns"), true); var buffer = add_label(box, ""); @@ -62,19 +62,19 @@ class ExcludeBox : Gtk.Box{ init_treeview(); init_actions(); - + refresh_treeview(); log_debug("ExcludeBox: ExcludeBox(): exit"); } public void set_users_box(UsersBox _users_box){ - + users_box = _users_box; } private void init_treeview(){ - + // treeview treeview = new TreeView(); treeview.get_selection().mode = SelectionMode.MULTIPLE; @@ -95,7 +95,7 @@ class ExcludeBox : Gtk.Box{ var col = new TreeViewColumn(); col.title = "+"; treeview.append_column(col); - + // radio_include var cell_radio = new Gtk.CellRendererToggle(); cell_radio.xpad = 2; @@ -104,24 +104,24 @@ class ExcludeBox : Gtk.Box{ col.pack_start (cell_radio, false); col.set_attributes(cell_radio, "active", 2); - + cell_radio.toggled.connect((cell, path)=>{ log_debug("cell_include.toggled()"); - + var model = (Gtk.ListStore) treeview.model; string pattern; TreeIter iter; model.get_iter_from_string (out iter, path); model.get (iter, 0, out pattern); - + if (!pattern.has_prefix("+ ")){ pattern = "+ %s".printf(pattern); } treeview_update_item(ref iter, pattern); - + save_changes(); }); @@ -136,17 +136,17 @@ class ExcludeBox : Gtk.Box{ cell_radio.radio = true; cell_radio.activatable = true; col.pack_start (cell_radio, false); - + col.set_attributes(cell_radio, "active", 3); cell_radio.toggled.connect((cell, path)=>{ log_debug("cell_exclude.toggled()"); - + var model = (Gtk.ListStore) treeview.model; string pattern; TreeIter iter; - + model.get_iter_from_string (out iter, path); model.get (iter, 0, out pattern); @@ -157,15 +157,15 @@ class ExcludeBox : Gtk.Box{ } treeview_update_item(ref iter, pattern); - + save_changes(); }); - + // column col = new TreeViewColumn(); col.title = _("Pattern"); treeview.append_column(col); - + // margin var cell_text = new CellRendererText (); cell_text.text = ""; @@ -179,7 +179,7 @@ class ExcludeBox : Gtk.Box{ // pattern cell_text = new CellRendererText (); col.pack_start (cell_text, false); - + col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{ string pattern; model.get (iter, 0, out pattern, -1); @@ -208,9 +208,9 @@ class ExcludeBox : Gtk.Box{ pattern = pattern[2:pattern.length]; } } - + model.set (iter, 0, pattern, -1); - + save_changes(); }); } @@ -223,7 +223,7 @@ class ExcludeBox : Gtk.Box{ var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); var button = add_button(hbox, _("Add"), _("Add custom pattern"), size_group, null); - + button.clicked.connect(()=>{ string pattern = gtk_inputbox( @@ -235,18 +235,18 @@ class ExcludeBox : Gtk.Box{ treeview_add_item(treeview, pattern); // don't strip Main.first_snapshot_size = 0; //re-calculate } - + save_changes(); }); - + button = add_button(hbox, _("Add Files"), _("Add files"), size_group, null); - + button.clicked.connect(()=>{ add_files_clicked(); }); button = add_button(hbox, _("Add Folders"), _("Add directories"), size_group, null); - + button.clicked.connect(()=>{ add_folder_clicked(); }); @@ -270,11 +270,11 @@ class ExcludeBox : Gtk.Box{ new ExcludeListSummaryWindow(false); }); } - + // actions - + private void remove_clicked(){ - + var sel = treeview.get_selection(); var store = (Gtk.ListStore) treeview.model; @@ -284,25 +284,25 @@ class ExcludeBox : Gtk.Box{ gtk_messagebox(title, message, parent_window, true); return; } - + TreeIter iter; var iter_list = new Gee.ArrayList(); - + bool iterExists = store.get_iter_first (out iter); while (iterExists) { if (sel.iter_is_selected (iter)){ string pattern; store.get (iter, 0, out pattern); - + App.exclude_list_user.remove(pattern); iter_list.add(iter); - + log_debug("removed item: %s".printf(pattern)); Main.first_snapshot_size = 0; //re-calculate } iterExists = store.iter_next (ref iter); } - + refresh_treeview(); save_changes(); @@ -344,17 +344,17 @@ class ExcludeBox : Gtk.Box{ if (!pattern.has_suffix("/***")){ pattern = "%s/***".printf(pattern); } - + /* NOTE: - + + /*** will include the directory along with the contents + / will include only the directory without the contents - + /*** will exclude the directory along with the contents / is same as exclude /*** */ - + if (!App.exclude_list_user.contains(pattern)){ App.exclude_list_user.add(pattern); treeview_add_item(treeview, pattern); @@ -378,21 +378,21 @@ class ExcludeBox : Gtk.Box{ foreach(string item in list){ string pattern = item; - + if (!pattern.has_suffix("/**")){ pattern = "%s/**".printf(pattern); } /* NOTE: - + + /** will include the directory along with the contents + / will include only the directory without the contents - + /** will exclude the directory contents but include the empty directory / will exclude the directory along with the contents */ - + if (!App.exclude_list_user.contains(pattern)){ App.exclude_list_user.add(pattern); treeview_add_item(treeview, pattern); @@ -407,17 +407,17 @@ class ExcludeBox : Gtk.Box{ save_changes(); } - + private SList browse_files(){ var list = new SList(); - + var dialog = new Gtk.FileChooserDialog( _("Select file(s)"), parent_window, Gtk.FileChooserAction.OPEN, "gtk-cancel", Gtk.ResponseType.CANCEL, "gtk-open", Gtk.ResponseType.ACCEPT); - + dialog.action = FileChooserAction.OPEN; dialog.set_transient_for(parent_window); dialog.local_only = true; @@ -429,7 +429,7 @@ class ExcludeBox : Gtk.Box{ if (resp != Gtk.ResponseType.CANCEL){ list = dialog.get_filenames(); } - + dialog.destroy(); return list; @@ -438,13 +438,13 @@ class ExcludeBox : Gtk.Box{ private SList browse_folder(){ var list = new SList(); - + var dialog = new Gtk.FileChooserDialog( _("Select directory"), parent_window, Gtk.FileChooserAction.SELECT_FOLDER, "gtk-cancel", Gtk.ResponseType.CANCEL, "gtk-open", Gtk.ResponseType.ACCEPT); - + dialog.action = FileChooserAction.SELECT_FOLDER; dialog.local_only = true; dialog.set_transient_for(parent_window); @@ -456,7 +456,7 @@ class ExcludeBox : Gtk.Box{ if (resp != Gtk.ResponseType.CANCEL){ list = dialog.get_filenames(); } - + dialog.destroy(); return list; @@ -465,7 +465,7 @@ class ExcludeBox : Gtk.Box{ // helpers public void refresh_treeview(){ - + var model = new Gtk.ListStore(4, typeof(string), typeof(string), typeof(bool), typeof(bool)); treeview.model = model; @@ -475,7 +475,7 @@ class ExcludeBox : Gtk.Box{ } private void treeview_add_item(Gtk.TreeView treeview, string pattern){ - + log_debug("treeview_add_item(): %s".printf(pattern)); TreeIter iter; @@ -494,7 +494,7 @@ class ExcludeBox : Gtk.Box{ } private void treeview_update_item(ref TreeIter iter, string pattern){ - + log_debug("treeview_update_item(): %s".printf(pattern)); bool include = pattern.has_prefix("+ "); @@ -507,7 +507,7 @@ class ExcludeBox : Gtk.Box{ } private void cell_exclude_text_edited(string path, string new_text) { - + string old_pattern; string new_pattern; @@ -540,10 +540,10 @@ class ExcludeBox : Gtk.Box{ if (!App.exclude_list_user.contains(pattern) && !App.exclude_list_default.contains(pattern) && !App.exclude_list_home.contains(pattern)){ - + App.exclude_list_user.add(pattern); } - + iterExists = store.iter_next(ref iter); } diff --git a/src/Gtk/ExcludeListSummaryWindow.vala b/src/Gtk/ExcludeListSummaryWindow.vala index 4d82459..c1fc417 100644 --- a/src/Gtk/ExcludeListSummaryWindow.vala +++ b/src/Gtk/ExcludeListSummaryWindow.vala @@ -33,19 +33,19 @@ using TeeJee.System; using TeeJee.Misc; class ExcludeListSummaryWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.Label lbl_list; private Gtk.Button btn_close; private bool for_restore = false; - + private int def_width = 500; private int def_height = 450; public ExcludeListSummaryWindow(bool _for_restore) { log_debug("ExcludeListSummaryWindow: ExcludeListSummaryWindow()"); - + this.title = _("Exclude List Summary"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -53,7 +53,7 @@ class ExcludeListSummaryWindow : Gtk.Window{ this.icon = IconManager.lookup("timeshift",16); for_restore = _for_restore; - + // vbox_main vbox_main = new Gtk.Box(Orientation.VERTICAL, 6); vbox_main.margin = 12; @@ -66,20 +66,20 @@ class ExcludeListSummaryWindow : Gtk.Window{ create_actions(); refresh(); - + show_all(); log_debug("ExcludeListSummaryWindow: ExcludeListSummaryWindow(): exit"); } - + private void create_actions(){ - + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); vbox_main.add(hbox); var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // close - + var img = new Image.from_stock("gtk-ok", Gtk.IconSize.BUTTON); btn_close = add_button(hbox, _("OK"), "", size_group, img); @@ -91,21 +91,21 @@ class ExcludeListSummaryWindow : Gtk.Window{ public void refresh(){ Gee.ArrayList list; - + if (for_restore){ list = App.create_exclude_list_for_restore(); } else{ list = App.create_exclude_list_for_backup(); } - + var txt = ""; foreach(var pattern in list){ if (pattern.strip().length > 0){ txt += "%s\n".printf(pattern); } } - + lbl_list.label = txt; } } diff --git a/src/Gtk/ExcludeMessageWindow.vala b/src/Gtk/ExcludeMessageWindow.vala index cbba683..517634c 100644 --- a/src/Gtk/ExcludeMessageWindow.vala +++ b/src/Gtk/ExcludeMessageWindow.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; public class ExcludeMessageWindow : Gtk.Dialog{ - + private Gtk.Box vbox_main; private Gtk.Box hbox_action; @@ -52,7 +52,7 @@ public class ExcludeMessageWindow : Gtk.Dialog{ public ExcludeMessageWindow () { log_debug("ExcludeMessageWindow: ExcludeMessageWindow()"); - + this.title = _("Excluded Directories"); this.window_position = WindowPosition.CENTER_ON_PARENT; this.set_destroy_with_parent (true); @@ -153,14 +153,14 @@ public class ExcludeMessageWindow : Gtk.Dialog{ } private void cell_exclude_text_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + string pattern; model.get (iter, 0, out pattern, -1); (cell as Gtk.CellRendererText).text = pattern.has_prefix("+ ") ? pattern[2:pattern.length] : pattern; } private void tv_exclude_add_item(string path){ - + string icon_name = null; TreeIter iter; @@ -181,7 +181,7 @@ public class ExcludeMessageWindow : Gtk.Dialog{ } private void btn_ok_clicked(){ - + this.response(Gtk.ResponseType.OK); return; } diff --git a/src/Gtk/FinishBox.vala b/src/Gtk/FinishBox.vala index 3da62bb..10a2d5e 100644 --- a/src/Gtk/FinishBox.vala +++ b/src/Gtk/FinishBox.vala @@ -33,23 +33,23 @@ using TeeJee.System; using TeeJee.Misc; class FinishBox : Gtk.Box{ - + private Gtk.Label lbl_header; private Gtk.Label lbl_message; - + private Gtk.Window parent_window; private bool show_notes = true; public FinishBox (Gtk.Window _parent_window, bool _show_notes) { log_debug("FinishBox: FinishBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; show_notes = _show_notes; - + // header if (show_notes){ lbl_header = add_label_header(this, _("Notes"), true); @@ -69,7 +69,7 @@ class FinishBox : Gtk.Box{ var msg = ""; string bullet = "• "; - + if (!show_notes){ if (App.scheduled){ msg += bullet + _("Scheduled snapshots are enabled. Snapshots will be created automatically for selected levels.") + "\n\n"; @@ -87,7 +87,7 @@ class FinishBox : Gtk.Box{ else{ msg += bullet + _("Restoring snapshots only replaces system files and settings. Non-hidden files and directories in user home directories will not be touched. This behaviour can be changed by adding a filter to include these files. Included files will be backed up when snapshot is created, and replaced when snapshot is restored.") + "\n\n"; } - + if (App.btrfs_mode){ msg += bullet + _("BTRFS snapshots are saved on the same disk from which it is created. If the system disk fails, snapshots will be lost along with the system. Save snapshots to an external non-system disk in RSYNC mode to guard against disk failures.") + "\n\n"; } @@ -96,7 +96,7 @@ class FinishBox : Gtk.Box{ msg += bullet + _("Saving snapshots to a non-system disk allows you to format and re-install the OS on the system disk without losing snapshots stored on it. You can even install another Linux distribution and later roll-back the previous distribution by restoring a snapshot.") + "\n\n"; } - + msg += "\n"; msg += "" + _("Close window to exit") + "\n\n"; diff --git a/src/Gtk/MainWindow.vala b/src/Gtk/MainWindow.vala index ba67a41..a7b43e9 100644 --- a/src/Gtk/MainWindow.vala +++ b/src/Gtk/MainWindow.vala @@ -48,7 +48,7 @@ class MainWindow : Gtk.Window{ private Gtk.Menu menu_extra; private SnapshotListBox snapshot_list_box; - + //statusbar private Gtk.ScrolledWindow statusbar; private Gtk.Image img_shield; @@ -60,7 +60,7 @@ class MainWindow : Gtk.Window{ private Gtk.Label lbl_free_space_subnote; private Gtk.ScrolledWindow scrolled_snap_count; private Gtk.ScrolledWindow scrolled_free_space; - + //timers private uint tmr_init; private int def_width = 800; @@ -71,7 +71,7 @@ class MainWindow : Gtk.Window{ public MainWindow () { log_debug("MainWindow: MainWindow()"); - + this.title = AppName; this.window_position = WindowPosition.CENTER; this.modal = true; @@ -101,7 +101,7 @@ class MainWindow : Gtk.Window{ } private bool init_delayed(){ - + if (tmr_init > 0){ Source.remove(tmr_init); tmr_init = 0; @@ -123,12 +123,12 @@ class MainWindow : Gtk.Window{ } log_debug("MainWindow(): init_delayed(): exit"); - + return false; } private void init_ui_toolbar(){ - + //toolbar toolbar = new Gtk.Toolbar (); toolbar.toolbar_style = ToolbarStyle.BOTH; @@ -163,7 +163,7 @@ class MainWindow : Gtk.Window{ toolbar.add(btn_delete_snapshot); btn_delete_snapshot.clicked.connect (delete_selected); - + //btn_browse_snapshot img = new Gtk.Image.from_icon_name("folder-symbolic", Gtk.IconSize.LARGE_TOOLBAR); btn_browse_snapshot = new Gtk.ToolButton (img, null); @@ -195,7 +195,7 @@ class MainWindow : Gtk.Window{ btn_wizard.clicked.connect (btn_wizard_clicked); // TODO: replace gtk icon names with desktop-neutral names - + //separator var separator = new Gtk.SeparatorToolItem(); separator.set_draw (false); @@ -216,13 +216,13 @@ class MainWindow : Gtk.Window{ } private void init_ui_snapshot_list(){ - + snapshot_list_box = new SnapshotListBox(this); snapshot_list_box.vexpand = true; vbox_main.add(snapshot_list_box); snapshot_list_box.delete_selected.connect(delete_selected); - + snapshot_list_box.mark_selected.connect(mark_selected); snapshot_list_box.browse_selected.connect(browse_selected); @@ -237,7 +237,7 @@ class MainWindow : Gtk.Window{ hbox_status.margin = 6; hbox_status.margin_top = 0; vbox_main.add(hbox_status); - + // scrolled var scrolled = new Gtk.ScrolledWindow(null, null); //scrolled.set_shadow_type (ShadowType.ETCHED_IN); @@ -247,7 +247,7 @@ class MainWindow : Gtk.Window{ scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER; hbox_status.add(scrolled); statusbar = scrolled; - + // hbox_shield var box = new Gtk.Box(Orientation.HORIZONTAL, 6); box.margin = 6; @@ -264,13 +264,13 @@ class MainWindow : Gtk.Window{ var vbox = new Gtk.Box(Orientation.VERTICAL, 6); //vbox.margin_right = 6; box.add (vbox); - + //lbl_shield lbl_shield = add_label(vbox, ""); //lbl_shield.margin_top = 6; lbl_shield.yalign = 0.5f; lbl_shield.hexpand = true; - + //lbl_shield_subnote lbl_shield_subnote = add_label(vbox, ""); lbl_shield_subnote.yalign = 0.5f; @@ -293,7 +293,7 @@ class MainWindow : Gtk.Window{ scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER; scrolled.set_no_show_all(true); hbox_status.add (scrolled); - + vbox = new Gtk.Box(Orientation.VERTICAL, 6); vbox.margin = 6; vbox.margin_left = 12; @@ -306,7 +306,7 @@ class MainWindow : Gtk.Window{ label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, true, true, 0); lbl_snap_count = label; - + label = new Gtk.Label(_("Snapshots")); label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, false, false, 0); @@ -316,7 +316,7 @@ class MainWindow : Gtk.Window{ label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, false, false, 0); lbl_snap_count_subnote = label; - + // free space //vbox = new Gtk.Box(Orientation.VERTICAL, 6); //vbox.set_no_show_all(true); @@ -329,7 +329,7 @@ class MainWindow : Gtk.Window{ scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER; scrolled.set_no_show_all(true); hbox_status.add (scrolled); - + vbox = new Gtk.Box(Orientation.VERTICAL, 6); vbox.margin = 6; vbox.margin_left = 12; @@ -342,7 +342,7 @@ class MainWindow : Gtk.Window{ label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, true, true, 0); lbl_free_space = label; - + label = new Gtk.Label(_("Available")); label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, false, false, 0); @@ -352,12 +352,12 @@ class MainWindow : Gtk.Window{ label.justify = Gtk.Justification.CENTER; vbox.pack_start(label, false, false, 0); lbl_free_space_subnote = label; - + // TODO: medium: add a refresh button for device when device is offline // TODO: low: refresh device list automatically when a device is plugged in } - + private bool menu_extra_popup(Gdk.EventButton? event){ menu_extra = new Gtk.Menu(); @@ -381,9 +381,9 @@ class MainWindow : Gtk.Window{ menu_item = create_menu_item(_("About"), "", "", 16); menu_extra.append(menu_item); menu_item.activate.connect(btn_about_clicked); - + menu_extra.show_all(); - + if (event != null) { menu_extra.popup (null, null, null, event.button, event.time); } @@ -397,9 +397,9 @@ class MainWindow : Gtk.Window{ private Gtk.MenuItem create_menu_item( string label_text, string icon_name_stock, string icon_name_custom, int icon_size, string tooltip_text = ""){ - + var menu_item = new Gtk.MenuItem(); - + var box = new Gtk.Box(Orientation.HORIZONTAL, 3); menu_item.add(box); @@ -411,17 +411,17 @@ class MainWindow : Gtk.Window{ return menu_item; } - + private Gtk.MenuItem create_menu_item_separator(){ - + var menu_item = new Gtk.MenuItem(); menu_item.sensitive = false; - + var box = new Gtk.Box(Orientation.HORIZONTAL, 3); menu_item.add(box); box.add(new Gtk.Separator(Gtk.Orientation.HORIZONTAL)); - + return menu_item; } @@ -433,7 +433,7 @@ class MainWindow : Gtk.Window{ snapshot_list_box.refresh(); update_statusbar(); - + ui_sensitive(true); return false; @@ -461,20 +461,20 @@ class MainWindow : Gtk.Window{ // check backup device ------------------------------- if (!App.live_system()){ - + if (!App.repo.available() || !App.repo.has_space()){ var title = App.repo.status_message; - + var msg = _("Select another device?"); - + var type = Gtk.MessageType.ERROR; var buttons_type = Gtk.ButtonsType.YES_NO; - + var dlg = new CustomMessageDialog(title, msg, type, this, buttons_type); var response = dlg.run(); dlg.destroy(); - + if (response == Gtk.ResponseType.YES){ this.delete_event.connect(on_delete_event); // reconnect this handler btn_wizard_clicked(); // open wizard @@ -490,15 +490,15 @@ class MainWindow : Gtk.Window{ } // context menu - + public void create_snapshot(){ if (check_if_deletion_running()){ return; } - + ui_sensitive(false); - + // check root device -------------- if (App.btrfs_mode && (App.check_btrfs_layout_system(this) == false)){ @@ -526,7 +526,7 @@ class MainWindow : Gtk.Window{ public void delete_selected(){ log_debug("main window: delete_selected()"); - + // check snapshot device ----------- if (!App.repo.available()){ @@ -554,7 +554,7 @@ class MainWindow : Gtk.Window{ return; } } - + // get selected snapshots if (!App.thread_delete_running){ @@ -579,7 +579,7 @@ class MainWindow : Gtk.Window{ // run wizard window ------------------ ui_sensitive(false); - + var win = new DeleteWindow(); win.set_transient_for(this); win.destroy.connect(()=>{ @@ -589,21 +589,21 @@ class MainWindow : Gtk.Window{ } public void mark_selected(){ - + TreeIter iter; bool is_success = true; // check selected count ---------------- var sel = snapshot_list_box.treeview.get_selection(); - + if (sel.count_selected_rows() == 0){ - + gtk_messagebox( _("No Snapshots Selected"), _("Select the snapshots to mark for deletion"), this, false); - + return; } @@ -612,11 +612,11 @@ class MainWindow : Gtk.Window{ var store = (Gtk.ListStore) snapshot_list_box.treeview.model; bool iterExists = store.get_iter_first (out iter); bool marked = false; - + while (iterExists && is_success) { - + if (sel.iter_is_selected (iter)){ - + Snapshot bak; store.get (iter, 0, out bak); // mark for deletion @@ -640,13 +640,13 @@ class MainWindow : Gtk.Window{ } public void browse_selected(){ - + var sel = snapshot_list_box.treeview.get_selection (); - + if (sel.count_selected_rows() == 0){ - + var f = File.new_for_path(App.repo.snapshots_path); - + if (f.query_exists()){ exo_open_folder(App.repo.snapshots_path); } @@ -660,10 +660,10 @@ class MainWindow : Gtk.Window{ var store = (Gtk.ListStore) snapshot_list_box.treeview.model; bool iterExists = store.get_iter_first (out iter); - + while (iterExists) { if (sel.iter_is_selected (iter)){ - + Snapshot bak; store.get (iter, 0, out bak); @@ -680,9 +680,9 @@ class MainWindow : Gtk.Window{ } public void view_snapshot_log(bool view_restore_log){ - + var sel = snapshot_list_box.treeview.get_selection (); - + if (sel.count_selected_rows() == 0){ gtk_messagebox( _("Select Snapshot"), @@ -695,11 +695,11 @@ class MainWindow : Gtk.Window{ var store = (Gtk.ListStore) snapshot_list_box.treeview.model; bool iterExists = store.get_iter_first (out iter); - + while (iterExists) { - + if (sel.iter_is_selected (iter)){ - + Snapshot bak; store.get (iter, 0, out bak); @@ -711,7 +711,7 @@ class MainWindow : Gtk.Window{ if (file_exists(log_file_name) || file_exists(log_file_name + "-changes")){ this.hide(); - + var win = new RsyncLogWindow(log_file_name); win.set_transient_for(this); win.destroy.connect(()=>{ @@ -730,17 +730,17 @@ class MainWindow : Gtk.Window{ if (check_if_deletion_running()){ return; } - + App.mirror_system = false; restore(); } private void btn_clone_clicked(){ - + if (check_if_deletion_running()){ return; } - + App.mirror_system = true; restore(); } @@ -750,20 +750,20 @@ class MainWindow : Gtk.Window{ if (App.thread_delete_running){ ui_sensitive(true); - + gtk_messagebox( _("Snapshot deletion in progress..."), _("Please wait for snapshots to be deleted."), this, true); - + ui_sensitive(false); - + var win = new DeleteWindow(); win.set_transient_for(this); win.destroy.connect(()=>{ refresh_all(); ui_sensitive(true); }); - + return true; } @@ -772,7 +772,7 @@ class MainWindow : Gtk.Window{ private void restore(){ - + TreeIter iter; TreeSelection sel; @@ -781,7 +781,7 @@ class MainWindow : Gtk.Window{ //check if single snapshot is selected ------------- sel = snapshot_list_box.treeview.get_selection(); - + if (sel.count_selected_rows() == 0){ gtk_messagebox( _("No snapshots selected"), @@ -796,14 +796,14 @@ class MainWindow : Gtk.Window{ this, false); return; } - + //get selected snapshot ------------------ Snapshot snapshot_to_restore = null; var store = (Gtk.ListStore) snapshot_list_box.treeview.model; bool iterExists = store.get_iter_first (out iter); - + while (iterExists) { if (sel.iter_is_selected (iter)){ store.get (iter, 0, out snapshot_to_restore); @@ -813,7 +813,7 @@ class MainWindow : Gtk.Window{ } if ((snapshot_to_restore != null) && (snapshot_to_restore.marked_for_deletion)){ - + gtk_messagebox( _("Invalid snapshot"), _("Selected snapshot is marked for deletion and cannot be restored"), @@ -828,7 +828,7 @@ class MainWindow : Gtk.Window{ } App.init_mount_list(); - + //show restore window ----------------- var window = new RestoreWindow(); @@ -845,14 +845,14 @@ class MainWindow : Gtk.Window{ private void btn_settings_clicked(){ log_debug("MainWindow: btn_settings_clicked()"); - + btn_settings.sensitive = false; btn_wizard.sensitive = false; this.hide(); bool btrfs_mode_prev = App.btrfs_mode; - + var win = new SettingsWindow(); win.set_transient_for(this); win.destroy.connect(()=>{ @@ -865,14 +865,14 @@ class MainWindow : Gtk.Window{ private void btn_wizard_clicked(){ log_debug("MainWindow: btn_wizard_clicked()"); - + btn_settings.sensitive = false; btn_wizard.sensitive = false; this.hide(); - + bool btrfs_mode_prev = App.btrfs_mode; - + var win = new SetupWizardWindow(); win.set_transient_for(this); win.destroy.connect(()=>{ @@ -905,18 +905,18 @@ class MainWindow : Gtk.Window{ } private void btn_view_app_logs_clicked(){ - + exo_open_folder(App.log_dir); } public void btn_donate_clicked(){ - + var dialog = new DonationWindow(this); dialog.show_all(); } private void btn_about_clicked (){ - + var dialog = new AboutWindow(this); dialog.set_transient_for (this); @@ -947,25 +947,25 @@ class MainWindow : Gtk.Window{ //dialog.license = ""; dialog.website = "https://teejeetech.com/"; dialog.website_label = "https://teejeetech.com/"; - + dialog.initialize(); dialog.show_all(); } private void ui_sensitive(bool enable){ - + toolbar.sensitive = enable; snapshot_list_box.treeview.sensitive = enable; gtk_set_busy(!enable, this); } private void update_statusbar(){ - + App.repo.check_status(); string message = App.repo.status_message; string details = App.repo.status_details; int status_code = App.repo.status_code; - + DateTime? last_snapshot_date = null; DateTime? oldest_snapshot_date = null; @@ -991,7 +991,7 @@ class MainWindow : Gtk.Window{ case SnapshotLocationStatus.NO_BTRFS_SYSTEM: set_shield_subnote(details); break; - + case SnapshotLocationStatus.HAS_SNAPSHOTS_NO_SPACE: case SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE: set_shield_subnote(_("Snapshots available for restore")); @@ -1059,13 +1059,13 @@ class MainWindow : Gtk.Window{ set_shield_subnote(_("Create snapshots manually or enable scheduled snapshots to protect your system")); } } - + break; } scrolled_snap_count.hide(); scrolled_free_space.hide(); - + switch (status_code){ case SnapshotLocationStatus.NO_SNAPSHOTS_NO_SPACE: case SnapshotLocationStatus.NO_SNAPSHOTS_HAS_SPACE: @@ -1073,14 +1073,14 @@ class MainWindow : Gtk.Window{ case SnapshotLocationStatus.HAS_SNAPSHOTS_HAS_SPACE: scrolled_snap_count.no_show_all = false; scrolled_snap_count.show_all(); - + lbl_snap_count.label = format_text_large("%0d".printf(App.repo.snapshots.size)); string mode = App.btrfs_mode ? "btrfs" : "rsync"; lbl_snap_count_subnote.label = format_text(mode, false, true, false); - + scrolled_free_space.no_show_all = false; scrolled_free_space.show_all(); - + lbl_free_space.label = format_text_large("%s".printf(format_file_size(App.repo.device.free_bytes))); string devname = "(??)"; @@ -1094,33 +1094,33 @@ class MainWindow : Gtk.Window{ } // ui helpers -------- - + private string format_text_large(string text){ - + return "" + text + ""; } - + private void set_shield_label( string text, bool is_bold = true, bool is_italic = false, bool is_large = true){ - + string msg = "%s".printf( (is_bold ? " weight=\"bold\"" : ""), (is_italic ? " style=\"italic\"" : ""), (is_large ? " size=\"x-large\"" : ""), escape_html(text)); - + lbl_shield.label = msg; } private void set_shield_subnote( string text, bool is_bold = false, bool is_italic = true, bool is_large = false){ - + string msg = "%s".printf( (is_bold ? " weight=\"bold\"" : ""), (is_italic ? " style=\"italic\"" : ""), (is_large ? " size=\"x-large\"" : ""), escape_html(text)); - + lbl_shield_subnote.label = msg; } } diff --git a/src/Gtk/MiscBox.vala b/src/Gtk/MiscBox.vala index cf6dd76..4f48f83 100644 --- a/src/Gtk/MiscBox.vala +++ b/src/Gtk/MiscBox.vala @@ -33,34 +33,34 @@ using TeeJee.System; using TeeJee.Misc; class MiscBox : Gtk.Box{ - + private Gtk.Window parent_window; private bool restore_mode = false; - + //private Gtk.CheckButton chk_include_btrfs_home; //private Gtk.CheckButton chk_enable_qgroups; - - + + public MiscBox (Gtk.Window _parent_window, bool _restore_mode) { log_debug("MiscBox: MiscBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; restore_mode = _restore_mode; - + var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 6); this.add(vbox); // ------------------------ - + init_date_format_option(vbox); refresh(); - + log_debug("MiscBox: MiscBox(): exit"); } @@ -80,7 +80,7 @@ class MiscBox : Gtk.Box{ var entry = new Gtk.Entry(); entry.hexpand = true; hbox.add(entry); - + var cell_pix = new Gtk.CellRendererPixbuf(); combo.pack_start (cell_pix, false); @@ -91,13 +91,13 @@ class MiscBox : Gtk.Box{ var now = new DateTime.local(2019, 8, 11, 20, 25, 43); combo.set_cell_data_func(cell_text, (cell_layout, cell, model, iter)=>{ - + string txt; model.get (iter, 0, out txt, -1); (cell as Gtk.CellRendererText).text = (txt.length == 0) ? _("Custom") : now.format(txt); }); - + // populate combo var model = new Gtk.ListStore(1, typeof(string)); combo.model = model; @@ -113,7 +113,7 @@ class MiscBox : Gtk.Box{ "%Y %b %d, %I:%M %p", // 2019 Aug 11, 08:00 PM "%c" // Sunday, 11 August 2019 08:00:00 PM IST }){ - + index++; model.append(out iter); model.set(iter, 0, fmt); @@ -122,11 +122,11 @@ class MiscBox : Gtk.Box{ active = index; } } - + if (active < 0){ - active = 0; + active = 0; } - + combo.active = active; combo.changed.connect((path) => { @@ -134,7 +134,7 @@ class MiscBox : Gtk.Box{ TreeIter iter_active; bool selected = combo.get_active_iter(out iter_active); if (!selected){ return; } - + TreeIter iter_combo; var store = (Gtk.ListStore) combo.model; @@ -145,9 +145,9 @@ class MiscBox : Gtk.Box{ if (txt.length > 0){ fmt = txt; } - + entry.text = fmt; - + entry.sensitive = (txt.length == 0); App.date_format = fmt; @@ -162,7 +162,7 @@ class MiscBox : Gtk.Box{ log_debug("saved date_format: %s".printf(App.date_format)); return false; }); - + show_all(); log_debug("MiscBox: init_date_format_option(): exit"); diff --git a/src/Gtk/RestoreBox.vala b/src/Gtk/RestoreBox.vala index df24546..4d483b0 100644 --- a/src/Gtk/RestoreBox.vala +++ b/src/Gtk/RestoreBox.vala @@ -39,7 +39,7 @@ using TeeJee.Misc; class RestoreBox : Gtk.Box{ public Gtk.Label lbl_header; - + private Gtk.Spinner spinner; public Gtk.Label lbl_msg; public Gtk.Label lbl_status; @@ -63,7 +63,7 @@ class RestoreBox : Gtk.Box{ public RestoreBox(Gtk.Window _parent_window) { log_debug("RestoreBox: RestoreBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -79,11 +79,11 @@ class RestoreBox : Gtk.Box{ var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6); add (hbox_status); - + spinner = new Gtk.Spinner(); spinner.active = true; hbox_status.add(spinner); - + //lbl_msg lbl_msg = add_label(hbox_status, _("Preparing...")); lbl_msg.hexpand = true; @@ -110,15 +110,15 @@ class RestoreBox : Gtk.Box{ var label = add_label(this, ""); label.vexpand = true; - + // add count labels --------------------------------- - + Gtk.SizeGroup sg_label = null; Gtk.SizeGroup sg_value = null; label = add_label(this, _("Files and directory counts:"), true); label.margin_bottom = 6; - + lbl_unchanged = add_count_label(this, _("No Change"), ref sg_label, ref sg_value); lbl_created = add_count_label(this, _("Created"), ref sg_label, ref sg_value); lbl_deleted = add_count_label(this, _("Deleted"), ref sg_label, ref sg_value); @@ -126,7 +126,7 @@ class RestoreBox : Gtk.Box{ label = add_label(this, _("Changed items:"), true); label.margin_bottom = 6; - + lbl_checksum = add_count_label(this, _("Checksum"), ref sg_label, ref sg_value); lbl_size = add_count_label(this, _("Size"), ref sg_label, ref sg_value); lbl_timestamp = add_count_label(this, _("Timestamp"), ref sg_label, ref sg_value); @@ -140,7 +140,7 @@ class RestoreBox : Gtk.Box{ private Gtk.Label add_count_label(Gtk.Box box, string text, ref Gtk.SizeGroup? sg_label, ref Gtk.SizeGroup? sg_value, int add_margin_bottom = 0){ - + var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6); box.add (hbox); @@ -178,7 +178,7 @@ class RestoreBox : Gtk.Box{ public bool restore(){ log_debug("RestoreBox: restore()"); - + if (App.restore_current_system && !App.dry_run){ parent_window.hide(); } @@ -189,7 +189,7 @@ class RestoreBox : Gtk.Box{ else{ lbl_header.label = format_text(_("Restoring Snapshot..."), true, false, true); } - + try { thread_is_running = true; Thread.create (restore_thread, true); @@ -205,20 +205,20 @@ class RestoreBox : Gtk.Box{ string status_line = ""; string last_status_line = ""; int remaining_counter = 10; - + while (thread_is_running){ status_line = escape_html(App.task.status_line); - + if (status_line != last_status_line){ - + lbl_status.label = status_line; last_status_line = status_line; status_line_counter = status_line_counter_default; } else{ status_line_counter--; - + if (status_line_counter < 0){ status_line_counter = status_line_counter_default; lbl_status.label = ""; @@ -231,16 +231,16 @@ class RestoreBox : Gtk.Box{ // time remaining remaining_counter--; - + if (remaining_counter == 0){ - + lbl_remaining.label = App.task.stat_time_remaining + " " + _("remaining"); remaining_counter = 10; - } - + } + if (fraction < 0.99){ - + progressbar.fraction = fraction; #if XAPP @@ -270,7 +270,7 @@ class RestoreBox : Gtk.Box{ #if XAPP XApp.set_window_progress(parent_window, 0); #endif - + if (App.restore_current_system && !App.dry_run){ parent_window.show(); } @@ -279,9 +279,9 @@ class RestoreBox : Gtk.Box{ return (App.task.exit_code == 0); } - + private void restore_thread(){ - + log_debug("RestoreBox: restore_thread()"); App.restore_snapshot(parent_window); thread_is_running = false; diff --git a/src/Gtk/RestoreDeviceBox.vala b/src/Gtk/RestoreDeviceBox.vala index 2fefc49..431cb07 100644 --- a/src/Gtk/RestoreDeviceBox.vala +++ b/src/Gtk/RestoreDeviceBox.vala @@ -39,7 +39,7 @@ class RestoreDeviceBox : Gtk.Box{ private Gtk.Box option_box; private Gtk.Label lbl_header_subvol; private bool show_volume_name = false; - + private Gtk.SizeGroup sg_mount_point = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); private Gtk.SizeGroup sg_device = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); private Gtk.SizeGroup sg_mount_options = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); @@ -49,7 +49,7 @@ class RestoreDeviceBox : Gtk.Box{ public RestoreDeviceBox (Gtk.Window _parent_window) { log_debug("RestoreDeviceBox: RestoreDeviceBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -63,9 +63,9 @@ class RestoreDeviceBox : Gtk.Box{ // buffer var label = add_label(hbox, ""); label.hexpand = true; - + // refresh device button - + Gtk.SizeGroup size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); var btn_refresh = add_button(hbox, _("Refresh"), "", size_group, null); btn_refresh.clicked.connect(()=>{ @@ -85,7 +85,7 @@ class RestoreDeviceBox : Gtk.Box{ } // headings - + hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); hbox.margin_top = 12; add(hbox); @@ -93,7 +93,7 @@ class RestoreDeviceBox : Gtk.Box{ label = add_label(hbox, _("Path") + " ", true, true); label.xalign = (float) 0.0; sg_mount_point.add_widget(label); - + label = add_label(hbox, _("Device") + " ", true, true); label.xalign = (float) 0.0; sg_device.add_widget(label); @@ -104,23 +104,23 @@ class RestoreDeviceBox : Gtk.Box{ lbl_header_subvol = label; // options - + option_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6); add(option_box); // bootloader - + add_boot_options(); // infobar - + create_infobar_location(); log_debug("RestoreDeviceBox: RestoreDeviceBox(): exit"); } public void refresh(bool reset_device_selections = true){ - + log_debug("RestoreDeviceBox: refresh()"); App.update_partitions(); create_device_selection_options(reset_device_selections); @@ -129,7 +129,7 @@ class RestoreDeviceBox : Gtk.Box{ } private void create_device_selection_options(bool reset_device_selections){ - + if (reset_device_selections){ App.init_mount_list(); } @@ -166,7 +166,7 @@ class RestoreDeviceBox : Gtk.Box{ var label = add_label(box, entry.mount_point, true); sg_mount_point.add_widget(label); - + var combo = add_device_combo(box, entry); sg_device.add_widget(combo); @@ -202,7 +202,7 @@ class RestoreDeviceBox : Gtk.Box{ if (dev.type == "disk"){ (cell as Gtk.CellRendererPixbuf).icon_name = IconManager.ICON_HARDDRIVE; } - + (cell as Gtk.CellRendererPixbuf).sensitive = (dev.type != "disk"); (cell as Gtk.CellRendererPixbuf).visible = (dev.type == "disk"); } @@ -219,16 +219,16 @@ class RestoreDeviceBox : Gtk.Box{ bool selected = combo.get_active_iter (out iter); if (!selected) { return true; } combo.model.get (iter, 0, out dev, -1); - + tooltip.set_icon_from_icon_name(IconManager.ICON_HARDDRIVE, tooltip_size); - + if (dev != null){ tooltip.set_markup(dev.tooltip_text()); } else{ tooltip.set_markup(_("Keep this mount path on the root filesystem")); } - + return true; }); @@ -244,11 +244,11 @@ class RestoreDeviceBox : Gtk.Box{ (cell as Gtk.CellRendererText).markup = _("Keep on Root Device"); } }); - + // populate combo var model = new Gtk.ListStore(2, typeof(Device), typeof(MountEntry)); combo.model = model; - + var active = -1; var index = -1; TreeIter iter; @@ -259,7 +259,7 @@ class RestoreDeviceBox : Gtk.Box{ model.set (iter, 0, null); model.set (iter, 1, entry); } - + foreach(var dev in App.partitions){ // skip disk and loop devices //if ((dev.type == "disk")||(dev.type == "loop")){ @@ -283,12 +283,12 @@ class RestoreDeviceBox : Gtk.Box{ continue; // skip parent partitions of unlocked volumes (luks) } } - + index++; model.append(out iter); model.set (iter, 0, dev); model.set (iter, 1, entry); - + if (entry.device != null){ if (dev.uuid == entry.device.uuid){ active = index; @@ -308,12 +308,12 @@ class RestoreDeviceBox : Gtk.Box{ } combo.active = active; - + combo.changed.connect((path) => { Device current_dev; MountEntry current_entry; - + TreeIter iter_active; bool selected = combo.get_active_iter (out iter_active); if (!selected){ @@ -328,7 +328,7 @@ class RestoreDeviceBox : Gtk.Box{ if (current_dev.is_encrypted_partition()){ log_debug("add_device_combo().changed: unlocking encrypted device.."); - + string msg_out, msg_err; var luks_unlocked = Device.luks_unlock( current_dev, "", "", parent_window, out msg_out, out msg_err); @@ -336,13 +336,13 @@ class RestoreDeviceBox : Gtk.Box{ if (luks_unlocked == null){ log_debug("add_device_combo().changed: failed to unlock"); - + // reset the selection - + if (current_entry.mount_point == "/"){ // reset to default device - + index = -1; for (bool next = store.get_iter_first (out iter_combo); next; next = store.iter_next (ref iter_combo)) { @@ -350,7 +350,7 @@ class RestoreDeviceBox : Gtk.Box{ Device dev_iter; store.get(iter_combo, 0, out dev_iter, -1); index++; - + if ((dev_iter != null) && (dev_iter.device == current_entry.device.device)){ combo.active = index; } @@ -359,15 +359,15 @@ class RestoreDeviceBox : Gtk.Box{ else{ combo.active = 0; // keep on root device } - + return; } else{ log_debug("add_device_combo().changed: unlocked"); - + // update current entry - + if (current_entry.mount_point == "/"){ App.dst_root = luks_unlocked; App.init_boot_options(); @@ -383,7 +383,7 @@ class RestoreDeviceBox : Gtk.Box{ } current_entry.device = current_dev; - + if (current_entry.mount_point == "/"){ App.init_boot_options(); } @@ -398,38 +398,38 @@ class RestoreDeviceBox : Gtk.Box{ var label = new Gtk.Label(""); label.vexpand = true; add(label); - + var hbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); hbox.margin_bottom = 24; add(hbox); var size_group = new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // close - + //var img = new Image.from_stock("gtk-dialog-warning", Gtk.IconSize.BUTTON); var button = add_button(hbox, _("Bootloader Options (Advanced)"), "", size_group, null); button.set_size_request(300, 40); button.set_tooltip_text(_("[Advanced Users Only] Change these settings only if the restored system fails to boot.")); var btn_boot_options = button; //hbox.set_child_packing(btn_boot_options, false, true, 6, Gtk.PackType.END); - + btn_boot_options.clicked.connect(()=>{ var win = new BootOptionsWindow(); win.set_transient_for(parent_window); //win.destroy.connect(()=>{ - + //});; }); } private void create_infobar_location(){ - + var infobar = new Gtk.InfoBar(); infobar.no_show_all = true; add(infobar); infobar_location = infobar; - + var content = (Gtk.Box) infobar.get_content_area (); var label = add_label(content, ""); lbl_infobar_location = label; @@ -438,27 +438,27 @@ class RestoreDeviceBox : Gtk.Box{ public bool check_and_mount_devices(){ // check if we are restoring the current system - + if (App.dst_root == App.sys_root){ return true; // all required devices are already mounted } - + // check if target device is selected for / - + foreach(var entry in App.mount_list){ if ((entry.mount_point == "/") && (entry.device == null)){ - + gtk_messagebox( _("Root device not selected"), _("Select the device for root file system (/)"), parent_window, true); - + return false; } } // verify that target device for / is not same as system in clone mode - + if (App.mirror_system){ foreach(var entry in App.mount_list){ @@ -473,14 +473,14 @@ class RestoreDeviceBox : Gtk.Box{ same = true; } } - + if (same){ - + gtk_messagebox( _("Target device is same as system device"), _("Select another device for root file system (/)"), parent_window, true); - + return false; } @@ -489,7 +489,7 @@ class RestoreDeviceBox : Gtk.Box{ } // check if /boot device is selected for luks partitions - + foreach(var entry in App.mount_list){ if ((entry.mount_point == "/boot") && (entry.device == null)){ @@ -517,7 +517,7 @@ class RestoreDeviceBox : Gtk.Box{ // check BTRFS subvolume layout -------------- bool supported = App.check_btrfs_layout(App.dst_root, App.dst_home, false); - + if (!supported){ var title = _("Unsupported Subvolume Layout") + " (%s)".printf(App.dst_root.device); diff --git a/src/Gtk/RestoreExcludeBox.vala b/src/Gtk/RestoreExcludeBox.vala index b1c30f7..65cc655 100644 --- a/src/Gtk/RestoreExcludeBox.vala +++ b/src/Gtk/RestoreExcludeBox.vala @@ -33,25 +33,25 @@ using TeeJee.System; using TeeJee.Misc; class RestoreExcludeBox : Gtk.Box{ - + //private Gtk.CheckButton chk_web; private Gtk.CheckButton chk_other; private Gtk.CheckButton chk_web; private Gtk.CheckButton chk_torrent; - + private Gtk.Window parent_window; public RestoreExcludeBox (Gtk.Window _parent_window) { log_debug("RestoreExcludeBox: RestoreExcludeBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; // app settings header -------------------------------- - + var label = add_label_header(this, _("Exclude Application Settings"), true); add_label(this, _("Select applications to exclude from restore")); @@ -63,7 +63,7 @@ class RestoreExcludeBox : Gtk.Box{ chk.margin_top = 12; chk.margin_bottom = 0; chk_web = chk; - + chk.toggled.connect(()=>{ foreach(var name in new string[]{ "chromium", "google-chrome", "mozilla", "midori", "epiphany", @@ -73,7 +73,7 @@ class RestoreExcludeBox : Gtk.Box{ } } }); - + label = add_label( this, _("Firefox, Chromium, Chrome, Opera, Epiphany, Midori"), false, true); label.margin_top = 0; @@ -87,12 +87,12 @@ class RestoreExcludeBox : Gtk.Box{ label.set_tooltip_text(tt); // torrent clients ---------------------------- - + chk = add_checkbox(this, _("Bittorrent Clients") + " (%s)".printf(_("Recommended"))); chk.active = true; chk.margin_bottom = 0; chk_torrent = chk; - + chk.toggled.connect(()=>{ foreach(var name in new string[]{ "deluge", "transmission" }){ @@ -101,7 +101,7 @@ class RestoreExcludeBox : Gtk.Box{ } } }); - + label = add_label(this, _("Deluge, Transmission"), false, true); label.margin_top = 0; label.margin_bottom = 6; @@ -114,7 +114,7 @@ class RestoreExcludeBox : Gtk.Box{ label.set_tooltip_text(tt); // all apps ---------------------------- - + chk = add_checkbox(this, _("Other applications (next page)")); chk_other = chk; @@ -127,13 +127,13 @@ class RestoreExcludeBox : Gtk.Box{ } public void refresh(){ - + chk_web.toggled(); chk_torrent.toggled(); } public bool show_all_apps(){ - + return chk_other.active; - } + } } diff --git a/src/Gtk/RestoreFinishBox.vala b/src/Gtk/RestoreFinishBox.vala index ed3c585..1bb0bac 100644 --- a/src/Gtk/RestoreFinishBox.vala +++ b/src/Gtk/RestoreFinishBox.vala @@ -38,9 +38,9 @@ class RestoreFinishBox : Gtk.Box{ private Gtk.Window parent_window; public RestoreFinishBox (Gtk.Window _parent_window) { - + log_debug("RestoreFinishBox: RestoreFinishBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -56,7 +56,7 @@ class RestoreFinishBox : Gtk.Box{ public void update_message(bool success, string message_header, string message_body){ // header ----------------------------------------- - + var txt = ""; if (message_header.length > 0){ @@ -70,7 +70,7 @@ class RestoreFinishBox : Gtk.Box{ else{ txt = _("Restore"); } - + if (success){ txt += " " + _("Completed"); } @@ -84,12 +84,12 @@ class RestoreFinishBox : Gtk.Box{ // body ------------------------------------------------------ var msg = ""; - + if (message_body.length > 0){ msg = message_body; } else { - + string bullet = "• "; if (App.btrfs_mode && App.restore_current_system){ @@ -105,7 +105,7 @@ class RestoreFinishBox : Gtk.Box{ msg += "\n"; msg += "" + _("Close window to exit") + "\n\n"; } - + lbl_message.label = msg; } diff --git a/src/Gtk/RestoreSummaryBox.vala b/src/Gtk/RestoreSummaryBox.vala index 40ca754..ca25b3c 100644 --- a/src/Gtk/RestoreSummaryBox.vala +++ b/src/Gtk/RestoreSummaryBox.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class RestoreSummaryBox : Gtk.Box{ - + public Gtk.Label lbl_devices; public Gtk.Label lbl_reboot; public Gtk.Label lbl_disclaimer; @@ -42,14 +42,14 @@ class RestoreSummaryBox : Gtk.Box{ public RestoreSummaryBox (Gtk.Window _parent_window) { log_debug("RestoreSummaryBox: RestoreSummaryBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; // devices - + add_label_header(this, _("Warning"), true); lbl_devices = add_label(this, "", false, false, false); @@ -58,11 +58,11 @@ class RestoreSummaryBox : Gtk.Box{ lbl_reboot = add_label(this, "", true, false, false); lbl_reboot.margin_bottom = 6; - + // disclaimer - + add_label_header(this, _("Disclaimer"), true); - + lbl_disclaimer = add_label(this, "", false, false, false); @@ -70,7 +70,7 @@ class RestoreSummaryBox : Gtk.Box{ } public void refresh(){ - + string msg_devices = ""; string msg_reboot = ""; string msg_disclaimer = ""; diff --git a/src/Gtk/RestoreWindow.vala b/src/Gtk/RestoreWindow.vala index 05ecba8..8ea2c28 100644 --- a/src/Gtk/RestoreWindow.vala +++ b/src/Gtk/RestoreWindow.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class RestoreWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.Notebook notebook; private Gtk.ButtonBox bbox_action; @@ -60,12 +60,12 @@ class RestoreWindow : Gtk.Window{ private int def_height = 500; private bool success = false; - public bool check_before_restore = true; - + public bool check_before_restore = true; + public RestoreWindow() { log_debug("RestoreWindow: RestoreWindow()"); - + this.title = App.mirror_system ? _("Clone System") : _("Restore Snapshot"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -85,7 +85,7 @@ class RestoreWindow : Gtk.Window{ notebook = add_notebook(vbox_main, false, false); Gtk.Label label; - + label = new Gtk.Label(_("Restore Device")); restore_device_box = new RestoreDeviceBox(this); restore_device_box.margin = 12; @@ -95,7 +95,7 @@ class RestoreWindow : Gtk.Window{ restore_exclude_box = new RestoreExcludeBox(this); restore_exclude_box.margin = 12; notebook.append_page (restore_exclude_box, label); - + label = new Gtk.Label(_("Exclude Apps")); exclude_apps_box = new ExcludeAppsBox(this); exclude_apps_box.margin = 12; @@ -142,7 +142,7 @@ class RestoreWindow : Gtk.Window{ log_debug("RestoreWindow: RestoreWindow(): exit"); } - + private bool init_delayed(){ if (tmr_init > 0){ @@ -160,44 +160,44 @@ class RestoreWindow : Gtk.Window{ private bool on_delete_event(Gdk.EventAny event){ save_changes(); - + return false; // close window } - + private void save_changes(){ - + App.cron_job_update(); } - + private void create_actions(){ - + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); vbox_main.add(hbox); - + var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); bbox.margin = 12; bbox.spacing = 6; bbox.hexpand = true; hbox.add(bbox); - + bbox_action = bbox; #if GTK3_18 - bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); + bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); #endif Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // previous - + btn_prev = add_button(bbox, _("Previous"), "", size_group, null); - + btn_prev.clicked.connect(()=>{ go_prev(); }); // next - + btn_next = add_button(bbox, _("Next"), "", size_group, null); btn_next.clicked.connect(()=>{ @@ -205,7 +205,7 @@ class RestoreWindow : Gtk.Window{ }); // close - + btn_close = add_button(bbox, _("Cancel"), "", size_group, null); btn_close.clicked.connect(()=>{ @@ -214,33 +214,33 @@ class RestoreWindow : Gtk.Window{ }); // cancel - + btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null); btn_cancel.clicked.connect(()=>{ if (!App.dry_run){ - + var title = _("Cancel restore?"); - + var msg = _("Cancelling the restore process will leave the target system in an inconsistent state. The system may fail to boot or you may run into various issues. After cancelling, you need to restore another snapshot, to bring the system to a consistent state. Click Yes to confirm."); - + var type = Gtk.MessageType.ERROR; var buttons_type = Gtk.ButtonsType.YES_NO; - + var dlg = new CustomMessageDialog(title, msg, type, this, buttons_type); var response = dlg.run(); dlg.destroy(); - + if (response != Gtk.ResponseType.YES){ return; } } - + if (App.task != null){ App.task.stop(AppStatus.CANCELLED); } - + this.destroy(); // TODO: low: Show error page }); @@ -250,23 +250,23 @@ class RestoreWindow : Gtk.Window{ } private void action_buttons_set_no_show_all(bool val){ - + btn_prev.no_show_all = val; btn_next.no_show_all = val; btn_close.no_show_all = val; btn_cancel.no_show_all = val; } - + // navigation ---------------------------------------------------- private void go_first(){ - + // set initial tab if (App.btrfs_mode){ - + if (App.snapshot_to_restore.subvolumes.has_key("@home")){ - + notebook.page = Tabs.USERS; } else { @@ -276,42 +276,42 @@ class RestoreWindow : Gtk.Window{ else{ notebook.page = Tabs.TARGET_DEVICE; } - + initialize_tab(); } - + private void go_prev(){ - + switch(notebook.page){ case Tabs.RESTORE_EXCLUDE: notebook.page = Tabs.TARGET_DEVICE; break; - + case Tabs.EXCLUDE_APPS: notebook.page = Tabs.RESTORE_EXCLUDE; //notebook.page = Tabs.TARGET_DEVICE; break; - + case Tabs.SUMMARY: notebook.page = Tabs.RESTORE_EXCLUDE; // go to parent (RESTORE_EXCLUDE) break; - + case Tabs.TARGET_DEVICE: case Tabs.RESTORE: case Tabs.FINISH: // btn_previous is disabled for this page break; } - + initialize_tab(); } - + private void go_next(){ - + if (!validate_current_tab()){ return; } - + switch(notebook.page){ case Tabs.TARGET_DEVICE: if (!App.btrfs_mode && check_before_restore){ @@ -321,20 +321,20 @@ class RestoreWindow : Gtk.Window{ notebook.page = Tabs.SUMMARY; } break; - + /*case Tabs.RESTORE_EXCLUDE: if (restore_exclude_box.show_all_apps()){ notebook.page = Tabs.EXCLUDE_APPS; } else{ notebook.page = Tabs.SUMMARY; - } + } break; - + case Tabs.EXCLUDE_APPS: notebook.page = Tabs.SUMMARY; break;*/ - + case Tabs.CHECK: notebook.page = Tabs.SHOW_LOG; break; @@ -350,18 +350,18 @@ class RestoreWindow : Gtk.Window{ case Tabs.SUMMARY: notebook.page = Tabs.RESTORE; break; - + case Tabs.RESTORE: notebook.page = Tabs.FINISH; break; - + case Tabs.FINISH: destroy(); break; } gtk_do_events(); - + initialize_tab(); } @@ -374,29 +374,29 @@ class RestoreWindow : Gtk.Window{ // show/hide actions ----------------------------------- action_buttons_set_no_show_all(false); - + switch(notebook.page){ case Tabs.RESTORE: - + btn_prev.hide(); btn_next.hide(); btn_close.hide(); - + btn_cancel.show(); - + break; - + case Tabs.CHECK: - + btn_prev.hide(); btn_next.hide(); btn_close.hide(); - + btn_cancel.show(); btn_cancel.sensitive = true; - + break; - + case Tabs.TARGET_DEVICE: case Tabs.RESTORE_EXCLUDE: case Tabs.EXCLUDE_APPS: @@ -408,7 +408,7 @@ class RestoreWindow : Gtk.Window{ btn_next.show(); btn_close.show(); btn_cancel.hide(); - + btn_prev.sensitive = false; btn_next.sensitive = true; btn_close.sensitive = true; @@ -416,25 +416,25 @@ class RestoreWindow : Gtk.Window{ break; case Tabs.SHOW_LOG: - + btn_prev.show(); btn_next.show(); btn_close.show(); btn_cancel.hide(); - + btn_prev.sensitive = false; btn_next.sensitive = true; btn_close.sensitive = true; - + break; - + case Tabs.FINISH: - + btn_prev.show(); btn_next.show(); btn_close.show(); btn_cancel.hide(); - + btn_prev.sensitive = false; btn_next.sensitive = false; btn_close.sensitive = true; @@ -443,28 +443,28 @@ class RestoreWindow : Gtk.Window{ } gtk_do_events(); - + // actions --------------------------------------------------- - + switch(notebook.page){ case Tabs.TARGET_DEVICE: restore_device_box.refresh(false); // false: App.init_mount_list() will be called before this window is shown break; - + case Tabs.RESTORE_EXCLUDE: restore_exclude_box.refresh(); break; - + case Tabs.EXCLUDE_APPS: exclude_apps_box.refresh(); break; - + case Tabs.CHECK: App.dry_run = true; success = check_box.restore(); go_next(); break; - + case Tabs.SHOW_LOG: if (file_exists(App.snapshot_to_restore.rsync_restore_log_file)){ log_box.open_log(App.snapshot_to_restore.rsync_restore_log_file); @@ -483,13 +483,13 @@ class RestoreWindow : Gtk.Window{ case Tabs.SUMMARY: summary_box.refresh(); break; - + case Tabs.RESTORE: App.dry_run = false; success = restore_box.restore(); go_next(); break; - + case Tabs.FINISH: restore_finish_box.update_message(success,"",""); btn_close.label = _("Close"); @@ -501,7 +501,7 @@ class RestoreWindow : Gtk.Window{ } private bool validate_current_tab(){ - + if (notebook.page == Tabs.TARGET_DEVICE){ bool ok = restore_device_box.check_and_mount_devices(); diff --git a/src/Gtk/RsyncLogBox.vala b/src/Gtk/RsyncLogBox.vala index 30e4f54..4006a04 100644 --- a/src/Gtk/RsyncLogBox.vala +++ b/src/Gtk/RsyncLogBox.vala @@ -46,7 +46,7 @@ public class RsyncLogBox : Gtk.Box { private Gtk.TreeViewColumn col_name; private Gtk.TreeViewColumn col_status; - + private string name_filter = ""; private string status_filter = ""; @@ -57,7 +57,7 @@ public class RsyncLogBox : Gtk.Box { public Gtk.Label lbl_status; public Gtk.Label lbl_remaining; public Gtk.ProgressBar progressbar; - + //private uint tmr_task = 0; private uint tmr_init = 0; private bool thread_is_running = false; @@ -68,11 +68,11 @@ public class RsyncLogBox : Gtk.Box { private Gtk.Window window; public RsyncLogBox(Gtk.Window _window) { - + GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around this.margin = 6; - + log_debug("RsyncLogBox: RsyncLogBox()"); window = _window; @@ -91,11 +91,11 @@ public class RsyncLogBox : Gtk.Box { create_progressbar(); create_filters(); - + create_treeview(); cmb_filter.changed.connect(() => { - + status_filter = gtk_combobox_get_value(cmb_filter, 0, ""); log_debug("combo_changed(): filter=%s".printf(status_filter)); @@ -103,7 +103,7 @@ public class RsyncLogBox : Gtk.Box { hbox_filter.sensitive = false; treeview.sensitive = false; - + log_debug("refilter(): start"); treefilter.refilter(); log_debug("refilter(): end"); @@ -138,7 +138,7 @@ public class RsyncLogBox : Gtk.Box { public bool init_delayed(){ log_debug("init_delayed()"); - + if (tmr_init > 0){ Source.remove(tmr_init); tmr_init = 0; @@ -156,7 +156,7 @@ public class RsyncLogBox : Gtk.Box { //gtk_set_busy(false, window); log_debug("init_delayed(): finish"); - + return false; } @@ -171,20 +171,20 @@ public class RsyncLogBox : Gtk.Box { } while (thread_is_running){ - + double fraction = (App.task.prg_count * 1.0) / App.task.prg_count_total; - + if (fraction < 0.99){ progressbar.fraction = fraction; } - + lbl_msg.label = _("Read %'d of %'d lines...").printf( App.task.prg_count, App.task.prg_count_total); - + sleep(500); gtk_do_events(); } - + lbl_msg.label = _("Populating list..."); gtk_do_events(); treeview_refresh(); @@ -198,9 +198,9 @@ public class RsyncLogBox : Gtk.Box { hbox_filter.no_show_all = false; hbox_filter.show_all(); } - + private void parse_log_file_thread(){ - + App.task = new RsyncTask(); loglist = App.task.parse_log(rsync_log_file); thread_is_running = false; @@ -211,23 +211,23 @@ public class RsyncLogBox : Gtk.Box { return thread_is_running; } } - + // create ui ----------------------------------------- private void create_progressbar(){ - + vbox_progress = new Gtk.Box(Orientation.VERTICAL, 6); this.add(vbox_progress); - + lbl_header_progress = add_label_header(vbox_progress, _("Parsing log file..."), true); - + var hbox_status = new Gtk.Box(Orientation.HORIZONTAL, 6); vbox_progress.add(hbox_status); - + spinner = new Gtk.Spinner(); spinner.active = true; hbox_status.add(spinner); - + //lbl_msg lbl_msg = add_label(hbox_status, _("Preparing...")); lbl_msg.hexpand = true; @@ -244,14 +244,14 @@ public class RsyncLogBox : Gtk.Box { // create filters ------------------------------------------- private void create_filters(){ - + log_debug("create_filters()"); - + var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); hbox.no_show_all = true; this.add(hbox); hbox_filter = hbox; - + //add_label(hbox, _("Filter:")); add_search_entry(hbox); @@ -262,10 +262,10 @@ public class RsyncLogBox : Gtk.Box { var label = add_label(hbox, ""); label.hexpand = true; - + var button = new Gtk.Button.with_label(_("Close")); hbox.add(button); - + button.clicked.connect(()=>{ window.destroy(); }); @@ -275,7 +275,7 @@ public class RsyncLogBox : Gtk.Box { _("Exclude Selected"), _("Exclude selected items from future snapshots (careful!)"), ref size_group, null); - + btn_exclude.clicked.connect(()=>{ if (flat_view){ gtk_messagebox(_("Cannot exclude files in flat view"), @@ -286,7 +286,7 @@ public class RsyncLogBox : Gtk.Box { else{ exclude_selected_items(); } - + treeview_refresh(); });*/ } @@ -298,7 +298,7 @@ public class RsyncLogBox : Gtk.Box { txt.hexpand = true; txt.margin = 0; hbox.add(txt); - + txt.placeholder_text = _("Filter by name or path"); txt_pattern = txt; @@ -332,17 +332,17 @@ public class RsyncLogBox : Gtk.Box { add_action_delayed(); return false; }); - + //txt.set_no_show_all(true); } private void add_combo(Gtk.Box hbox){ - + // combo var combo = new Gtk.ComboBox (); hbox.add(combo); cmb_filter = combo; - + var cell_text = new CellRendererText (); cell_text.text = ""; combo.pack_start (cell_text, false); @@ -358,10 +358,10 @@ public class RsyncLogBox : Gtk.Box { cmb_filter.model = model; TreeIter iter; - + model.append(out iter); model.set (iter, 0, "", 1, _("All Files")); - + model.append(out iter); model.set (iter, 0, "created", 1, "%s".printf(App.dry_run ? _("Create") : _("Created"))); @@ -369,7 +369,7 @@ public class RsyncLogBox : Gtk.Box { model.append(out iter); model.set (iter, 0, "deleted", 1, "%s".printf(App.dry_run ? _("Delete") : _("Deleted"))); } - + model.append(out iter); string txt = ""; @@ -382,7 +382,7 @@ public class RsyncLogBox : Gtk.Box { else{ txt = _("Changed"); } - + model.set (iter, 0, "changed", 1, "%s".printf(txt)); if (!App.dry_run){ @@ -399,20 +399,20 @@ public class RsyncLogBox : Gtk.Box { model.append(out iter); model.set (iter, 0, "group", 1, " â”” %s".printf(_("Group"))); } - + cmb_filter.active = 0; } private uint tmr_action = 0; - + private void add_action_delayed(){ - + clear_action_delayed(); tmr_action = Timeout.add(200, execute_action); } private void clear_action_delayed(){ - + if (tmr_action > 0){ Source.remove(tmr_action); tmr_action = 0; @@ -424,9 +424,9 @@ public class RsyncLogBox : Gtk.Box { clear_action_delayed(); name_filter = txt_pattern.text; - + treefilter.refilter(); - + return false; } @@ -478,7 +478,7 @@ public class RsyncLogBox : Gtk.Box { cell_pix.stock_size = Gtk.IconSize.MENU; col.pack_start(cell_pix, false); col.set_attributes(cell_pix, "pixbuf", 3); - + // cell text var cell_text = new Gtk.CellRendererText (); col.pack_start (cell_text, false); @@ -495,13 +495,13 @@ public class RsyncLogBox : Gtk.Box { col.expand = true; treeview.append_column(col); col_name = col; - + // cell icon var cell_pix = new Gtk.CellRendererPixbuf(); cell_pix.stock_size = Gtk.IconSize.MENU; col.pack_start(cell_pix, false); col.set_attributes(cell_pix, "pixbuf", 1); - + // cell text var cell_text = new Gtk.CellRendererText (); cell_text.ellipsize = Pango.EllipsizeMode.END; @@ -518,20 +518,20 @@ public class RsyncLogBox : Gtk.Box { col.min_width = 20; treeview.append_column(col); //var col_spacer = col; - + // cell text var cell_text = new Gtk.CellRendererText (); col.pack_start (cell_text, false); } - + private void treeview_refresh() { - + log_debug("treeview_refresh(): 0"); var tmr = timer_start(); hbox_filter.sensitive = false; - + gtk_set_busy(true, window); var model = new Gtk.ListStore(5, @@ -545,7 +545,7 @@ public class RsyncLogBox : Gtk.Box { TreeIter iter0; var spath = "%s/localhost".printf(file_parent(rsync_log_file)); - + foreach(var item in loglist) { if (App.dry_run){ @@ -554,7 +554,7 @@ public class RsyncLogBox : Gtk.Box { string status = ""; Gdk.Pixbuf status_icon = null; - + if (is_restore_log){ switch(item.file_status){ @@ -604,7 +604,7 @@ public class RsyncLogBox : Gtk.Box { if (!is_restore_log){ relpath = relpath[1:relpath.length]; // show relative path; remove / prefix } - + // add row model.append(out iter0); model.set(iter0, 0, item); @@ -613,11 +613,11 @@ public class RsyncLogBox : Gtk.Box { model.set(iter0, 3, status_icon); model.set(iter0, 4, status); } - + treefilter = new Gtk.TreeModelFilter(model, null); treefilter.set_visible_func(filter_packages_func); treeview.set_model(treefilter); - + //treeview.set_model(model); //treeview.columns_autosize(); @@ -628,7 +628,7 @@ public class RsyncLogBox : Gtk.Box { } private bool filter_packages_func (Gtk.TreeModel model, Gtk.TreeIter iter) { - + FileItem item; model.get (iter, 0, out item, -1); @@ -641,9 +641,9 @@ public class RsyncLogBox : Gtk.Box { var spath = "%s/localhost".printf(file_parent(rsync_log_file)); var relpath = item.file_path[spath.length:item.file_path.length]; - + if (!relpath.down().contains(name_filter)){ - + return false; } } @@ -677,7 +677,7 @@ public class RsyncLogBox : Gtk.Box { App.exclude_list_user.clear(); // TODO: medium: exclude selected items: not working - + // add include list TreeIter iter; var store = (Gtk.ListStore) treeview.model; @@ -694,14 +694,14 @@ public class RsyncLogBox : Gtk.Box { else{ //pattern = "%s/***".printf(pattern); } - + if (!App.exclude_list_user.contains(pattern) && !App.exclude_list_default.contains(pattern) && !App.exclude_list_home.contains(pattern)){ - + list.add(pattern); } - + iterExists = store.iter_next (ref iter); } diff --git a/src/Gtk/RsyncLogWindow.vala b/src/Gtk/RsyncLogWindow.vala index 970de37..528e0eb 100644 --- a/src/Gtk/RsyncLogWindow.vala +++ b/src/Gtk/RsyncLogWindow.vala @@ -45,7 +45,7 @@ public class RsyncLogWindow : Window { public RsyncLogWindow(string _rsync_log_file) { log_debug("RsyncLogWindow: RsyncLogWindow()"); - + this.title = _("Rsync Log Viewer"); this.window_position = Gtk.WindowPosition.CENTER_ON_PARENT; this.set_default_size(def_width, def_height); @@ -56,10 +56,10 @@ public class RsyncLogWindow : Window { this.delete_event.connect(on_delete_event); rsync_log_file = _rsync_log_file; - + logbox = new RsyncLogBox(this); this.add(logbox); - + show_all(); logbox.open_log(rsync_log_file); @@ -68,7 +68,7 @@ public class RsyncLogWindow : Window { } private bool on_delete_event(Gdk.EventAny event){ - + if (logbox.is_running){ return true; // keep window open } diff --git a/src/Gtk/ScheduleBox.vala b/src/Gtk/ScheduleBox.vala index 5df2d79..39f33fc 100644 --- a/src/Gtk/ScheduleBox.vala +++ b/src/Gtk/ScheduleBox.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class ScheduleBox : Gtk.Box{ - + private Gtk.Image img_shield; private Gtk.Label lbl_shield; private Gtk.Label lbl_shield_subnote; @@ -42,25 +42,25 @@ class ScheduleBox : Gtk.Box{ private Gtk.SizeGroup sg_count; private Gtk.CheckButton chk_cron; - + private Gtk.Window parent_window; - + public ScheduleBox (Gtk.Window _parent_window) { log_debug("ScheduleBox: ScheduleBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 12; - + add_label_header(this, _("Select Snapshot Levels"), true); Gtk.CheckButton chk_m, chk_w, chk_d, chk_h, chk_b = null; Gtk.SpinButton spin_m, spin_w, spin_d, spin_h, spin_b; // monthly - + add_schedule_option(this, _("Monthly"), _("Create one per month"), out chk_m, out spin_m); chk_m.active = App.schedule_monthly; @@ -76,9 +76,9 @@ class ScheduleBox : Gtk.Box{ spin_m.value_changed.connect(()=>{ App.count_monthly = (int) spin_m.get_value(); }); - + // weekly - + add_schedule_option(this, _("Weekly"), _("Create one per week"), out chk_w, out spin_w); chk_w.active = App.schedule_weekly; @@ -96,7 +96,7 @@ class ScheduleBox : Gtk.Box{ }); // daily - + add_schedule_option(this, _("Daily"), _("Create one per day"), out chk_d, out spin_d); chk_d.active = App.schedule_daily; @@ -114,7 +114,7 @@ class ScheduleBox : Gtk.Box{ }); // hourly - + add_schedule_option(this, _("Hourly"), _("Create one per hour"), out chk_h, out spin_h); chk_h.active = App.schedule_hourly; @@ -132,7 +132,7 @@ class ScheduleBox : Gtk.Box{ }); // boot - + add_schedule_option(this, _("Boot"), _("Create one per boot"), out chk_b, out spin_b); chk_b.active = App.schedule_boot; @@ -150,14 +150,14 @@ class ScheduleBox : Gtk.Box{ }); // cron emails -------------------------------------------------------------------- - + chk_cron = add_checkbox(this, _("Stop cron emails for scheduled tasks")); //chk_cron.hexpand = true; chk_cron.set_tooltip_text(_("The cron service sends the output of scheduled tasks as an email to the current user. Select this option to suppress the emails for cron tasks created by Timeshift.")); chk_cron.margin = 6; - chk_cron.margin_top = 12; - + chk_cron.margin_top = 12; + chk_cron.active = App.stop_cron_emails; chk_cron.toggled.connect(()=>{ App.stop_cron_emails = chk_cron.active; @@ -172,9 +172,9 @@ class ScheduleBox : Gtk.Box{ var label = new Gtk.Label(""); label.vexpand = true; add(label); - + // message area ------------------------------------------------------------------- - + var scrolled = new Gtk.ScrolledWindow(null, null); scrolled.set_shadow_type (ShadowType.ETCHED_IN); scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER; @@ -193,14 +193,14 @@ class ScheduleBox : Gtk.Box{ scrolled.add(label); // status area -------------------------------------------------------------------- - + scrolled = new Gtk.ScrolledWindow(null, null); scrolled.set_shadow_type (ShadowType.ETCHED_IN); scrolled.hscrollbar_policy = Gtk.PolicyType.NEVER; scrolled.vscrollbar_policy = Gtk.PolicyType.NEVER; scrolled.set_size_request(-1, 100); add(scrolled); - + // hbox var hbox = new Gtk.Box(Orientation.HORIZONTAL, 6); hbox.margin = 6; @@ -216,7 +216,7 @@ class ScheduleBox : Gtk.Box{ var vbox = new Gtk.Box(Orientation.VERTICAL, 6); vbox.margin_top = 6; hbox.add (vbox); - + // lbl_shield lbl_shield = add_label(vbox, ""); lbl_shield.yalign = 0.5f; @@ -237,25 +237,25 @@ class ScheduleBox : Gtk.Box{ private void set_shield_label( string text, bool is_bold = true, bool is_italic = false, bool is_large = true){ - + string msg = "%s".printf( (is_bold ? " weight=\"bold\"" : ""), (is_italic ? " style=\"italic\"" : ""), (is_large ? " size=\"x-large\"" : ""), escape_html(text)); - + lbl_shield.label = msg; } private void set_shield_subnote( string text, bool is_bold = false, bool is_italic = true, bool is_large = false){ - + string msg = "%s".printf( (is_bold ? " weight=\"bold\"" : ""), (is_italic ? " style=\"italic\"" : ""), (is_large ? " size=\"x-large\"" : ""), escape_html(text)); - + lbl_shield_subnote.label = msg; } @@ -274,11 +274,11 @@ class ScheduleBox : Gtk.Box{ sg_subtitle = new Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL); sg_count = new Gtk.SizeGroup(Gtk.SizeGroupMode.HORIZONTAL); } - + var txt = "%s".printf(period); chk = add_checkbox(hbox, txt); sg_title.add_widget(chk); - + var tt = _("Number of snapshots to keep.\nOlder snapshots will be removed once this limit is exceeded."); var label = add_label(hbox, " " + _("Keep")); label.set_tooltip_text(tt); @@ -286,7 +286,7 @@ class ScheduleBox : Gtk.Box{ var spin2 = add_spin(hbox, 1, 999, 10); spin2.set_tooltip_text(tt); sg_count.add_widget(spin2); - + spin2.notify["sensitive"].connect(()=>{ label.sensitive = spin2.sensitive; }); @@ -295,20 +295,20 @@ class ScheduleBox : Gtk.Box{ } public void update_statusbar(){ - + if (App.schedule_monthly || App.schedule_weekly || App.schedule_daily || App.schedule_hourly || App.schedule_boot){ img_shield.surface = IconManager.lookup_surface(IconManager.SHIELD_HIGH, IconManager.SHIELD_ICON_SIZE, img_shield.scale_factor); - + set_shield_label(_("Scheduled snapshots are enabled")); set_shield_subnote(_("Snapshots will be created at selected intervals if snapshot disk has enough space (> 1 GB)")); } else{ img_shield.surface = IconManager.lookup_surface(IconManager.SHIELD_LOW, IconManager.SHIELD_ICON_SIZE, img_shield.scale_factor); - + set_shield_label(_("Scheduled snapshots are disabled")); set_shield_subnote(_("Select the intervals for creating snapshots")); } diff --git a/src/Gtk/SettingsWindow.vala b/src/Gtk/SettingsWindow.vala index 8bf74d3..0b5cea3 100644 --- a/src/Gtk/SettingsWindow.vala +++ b/src/Gtk/SettingsWindow.vala @@ -33,22 +33,22 @@ using TeeJee.System; using TeeJee.Misc; class SettingsWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.StackSwitcher switcher; private Gtk.Stack stack; - + private SnapshotBackendBox backend_box; private BackupDeviceBox backup_dev_box; private ScheduleBox schedule_box; private ExcludeBox exclude_box; private UsersBox users_box; private MiscBox misc_box; - + private uint tmr_init; private int def_width = 500; private int def_height = 500; - + public SettingsWindow() { log_debug("SettingsWindow: SettingsWindow()"); @@ -71,7 +71,7 @@ class SettingsWindow : Gtk.Window{ hbox.set_layout (Gtk.ButtonBoxStyle.CENTER); hbox.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR); vbox_main.add(hbox); - + switcher = new Gtk.StackSwitcher(); switcher.margin = 6; hbox.add (switcher); @@ -82,10 +82,10 @@ class SettingsWindow : Gtk.Window{ vbox_main.add(stack); switcher.set_stack(stack); - + backend_box = new SnapshotBackendBox(this); stack.add_titled (backend_box, "type", _("Type")); - + backup_dev_box = new BackupDeviceBox(this); stack.add_titled (backup_dev_box, "location", _("Location")); @@ -97,7 +97,7 @@ class SettingsWindow : Gtk.Window{ exclude_box.set_users_box(users_box); misc_box = new MiscBox(this, false); - + stack.add_titled (users_box, "users", _("Users")); stack.add_titled (exclude_box, "filters", _("Filters")); @@ -115,16 +115,16 @@ class SettingsWindow : Gtk.Window{ //var hbox = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL); var bbox = new Gtk.ButtonBox(Gtk.Orientation.HORIZONTAL); vbox_main.add(bbox); - + #if GTK3_18 bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); #endif - + var btn_ok = new Button.with_label(_("OK")); btn_ok.margin = 12; btn_ok.set_size_request(100, -1); bbox.add(btn_ok); - + btn_ok.clicked.connect(()=>{ save_changes(); this.destroy(); @@ -146,25 +146,25 @@ class SettingsWindow : Gtk.Window{ backend_box.refresh(); stack.set_visible_child_name("type"); - + this.resize(def_width, def_height); - + //backup_dev_box.refresh(); //will be triggerred indirectly - + return false; } - + private bool on_delete_event(Gdk.EventAny event){ - + save_changes(); return false; // close window } - + private void save_changes(){ - + exclude_box.save_changes(); - + App.cron_job_update(); //App.check_encrypted_home(this); diff --git a/src/Gtk/SetupWizardWindow.vala b/src/Gtk/SetupWizardWindow.vala index 77200c2..6056c08 100644 --- a/src/Gtk/SetupWizardWindow.vala +++ b/src/Gtk/SetupWizardWindow.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class SetupWizardWindow : Gtk.Window{ - + private Gtk.Box vbox_main; private Gtk.Notebook notebook; @@ -56,11 +56,11 @@ class SetupWizardWindow : Gtk.Window{ private uint tmr_init; private int def_width = 600; private int def_height = 500; - + public SetupWizardWindow() { log_debug("SetupWizardWindow: SetupWizardWindow()"); - + this.title = _("Setup Wizard"); this.window_position = WindowPosition.CENTER; this.modal = true; @@ -68,7 +68,7 @@ class SetupWizardWindow : Gtk.Window{ this.icon = IconManager.lookup("timeshift",16); this.delete_event.connect(on_delete_event); - + // vbox_main vbox_main = new Gtk.Box(Orientation.VERTICAL, 6); vbox_main.margin = 0; @@ -95,7 +95,7 @@ class SetupWizardWindow : Gtk.Window{ backend_box = new SnapshotBackendBox(this); backend_box.margin = 12; notebook.append_page (backend_box, label); - + label = new Gtk.Label(_("Estimate")); estimate_box = new EstimateBox(this); estimate_box.margin = 12; @@ -123,7 +123,7 @@ class SetupWizardWindow : Gtk.Window{ notebook.append_page (finish_box, label); // TODO: Add a tab for excluding browser cache and other items - + create_actions(); show_all(); @@ -132,7 +132,7 @@ class SetupWizardWindow : Gtk.Window{ log_debug("SetupWizardWindow: SetupWizardWindow(): exit"); } - + private bool init_delayed(){ if (tmr_init > 0){ @@ -158,40 +158,40 @@ class SetupWizardWindow : Gtk.Window{ } save_changes(); - + return false; // close window } - + private void save_changes(){ - + App.cron_job_update(); App.first_run = false; - + //App.check_encrypted_home(this); //App.check_encrypted_private_dirs(this); } - + private void create_actions(){ var hbox = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 6); vbox_main.add(hbox); - + var bbox = new Gtk.ButtonBox (Gtk.Orientation.HORIZONTAL); bbox.margin = 12; bbox.spacing = 6; bbox.hexpand = true; hbox.add(bbox); - + #if GTK3_18 bbox.set_layout (Gtk.ButtonBoxStyle.CENTER); #endif - + Gtk.SizeGroup size_group = null; //new Gtk.SizeGroup(SizeGroupMode.HORIZONTAL); - + // previous - + btn_prev = add_button(bbox, _("Previous"), "", size_group, null); btn_prev.clicked.connect(()=>{ @@ -199,7 +199,7 @@ class SetupWizardWindow : Gtk.Window{ }); // next - + btn_next = add_button(bbox, _("Next"), "", size_group, null); btn_next.clicked.connect(()=>{ @@ -207,7 +207,7 @@ class SetupWizardWindow : Gtk.Window{ }); // close - + btn_close = add_button(bbox, _("Finish"), "", size_group, null); btn_close.clicked.connect(()=>{ @@ -216,40 +216,40 @@ class SetupWizardWindow : Gtk.Window{ }); // cancel - + btn_cancel = add_button(bbox, _("Cancel"), "", size_group, null); btn_cancel.clicked.connect(()=>{ if (App.task != null){ App.task.stop(AppStatus.CANCELLED); } - + this.destroy(); // TODO: Show error page }); btn_prev.hexpand = btn_next.hexpand = btn_close.hexpand = true; btn_cancel.hexpand = true; - + action_buttons_set_no_show_all(true); } private void action_buttons_set_no_show_all(bool val){ - + btn_prev.no_show_all = val; btn_next.no_show_all = val; btn_close.no_show_all = val; btn_cancel.no_show_all = val; } - + // navigation private void go_first(){ - + // set initial tab notebook.page = Tabs.SNAPSHOT_BACKEND; - + /*if (App.live_system()){ // skip estimate_box and go to backup_dev_box notebook.page = Tabs.SNAPSHOT_BACKEND; @@ -265,9 +265,9 @@ class SetupWizardWindow : Gtk.Window{ initialize_tab(); } - + private void go_prev(){ - + switch(notebook.page){ case Tabs.SNAPSHOT_BACKEND: case Tabs.ESTIMATE: @@ -286,12 +286,12 @@ class SetupWizardWindow : Gtk.Window{ notebook.page = Tabs.USERS; break; } - + initialize_tab(); } - + private void go_next(){ - + if (!validate_current_tab()){ return; } @@ -305,11 +305,11 @@ class SetupWizardWindow : Gtk.Window{ notebook.page = Tabs.ESTIMATE; // rsync mode only } break; - + case Tabs.ESTIMATE: notebook.page = Tabs.BACKUP_DEVICE; break; - + case Tabs.BACKUP_DEVICE: if (App.live_system()){ destroy(); @@ -318,7 +318,7 @@ class SetupWizardWindow : Gtk.Window{ notebook.page = Tabs.SCHEDULE; } break; - + case Tabs.SCHEDULE: notebook.page = Tabs.USERS; schedule_accepted = true; @@ -327,12 +327,12 @@ class SetupWizardWindow : Gtk.Window{ case Tabs.USERS: notebook.page = Tabs.FINISH; break; - + case Tabs.FINISH: // btn_next is disabled for this page break; } - + initialize_tab(); } @@ -348,13 +348,13 @@ class SetupWizardWindow : Gtk.Window{ // show/hide actions ----------------------------------- action_buttons_set_no_show_all(false); - + btn_cancel.hide(); // TODO: remove this btn_prev.show(); btn_next.show(); btn_close.show(); - + switch(notebook.page){ case Tabs.SNAPSHOT_BACKEND: btn_prev.sensitive = false; @@ -421,10 +421,10 @@ class SetupWizardWindow : Gtk.Window{ } else if (notebook.page == Tabs.BACKUP_DEVICE){ if (!App.repo.available() || !App.repo.has_space()){ - + gtk_messagebox(App.repo.status_message, App.repo.status_details, this, true); - + return false; } } diff --git a/src/Gtk/SnapshotBackendBox.vala b/src/Gtk/SnapshotBackendBox.vala index 7514454..09bbd0f 100755 --- a/src/Gtk/SnapshotBackendBox.vala +++ b/src/Gtk/SnapshotBackendBox.vala @@ -33,18 +33,18 @@ using TeeJee.System; using TeeJee.Misc; class SnapshotBackendBox : Gtk.Box{ - + private Gtk.RadioButton opt_rsync; private Gtk.RadioButton opt_btrfs; private Gtk.Label lbl_description; private Gtk.Window parent_window; - + public signal void type_changed(); public SnapshotBackendBox (Gtk.Window _parent_window) { log_debug("SnapshotBackendBox: SnapshotBackendBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -64,7 +64,7 @@ class SnapshotBackendBox : Gtk.Box{ var vbox = new Gtk.Box(Gtk.Orientation.VERTICAL, 6); //hbox.homogeneous = true; add(vbox); - + add_opt_rsync(vbox); add_opt_btrfs(vbox); @@ -113,28 +113,28 @@ class SnapshotBackendBox : Gtk.Box{ } private bool check_for_btrfs_tools(){ - + if (!cmd_exists("btrfs")){ - + string msg = _("The 'btrfs' command is not available on your system. Install the 'btrfs-tools' package and try again."); string title = _("BTRFS Tools Not Found"); gtk_set_busy(false, parent_window); gtk_messagebox(title, msg, parent_window, true); - + return false; } else{ return true; } } - + private void add_description(){ Gtk.Expander expander = new Gtk.Expander(_("Help")); expander.use_markup = true; expander.margin_top = 12; this.add(expander); - + // scrolled var scrolled = new ScrolledWindow(null, null); scrolled.set_shadow_type (ShadowType.ETCHED_IN); @@ -161,16 +161,16 @@ class SnapshotBackendBox : Gtk.Box{ private void update_description(){ string bullet = "• "; - + if (opt_btrfs.active){ string txt = "" + _("BTRFS Snapshots") + "\n\n"; txt += bullet + _("Snapshots are created using the built-in features of the BTRFS file system.") + "\n\n"; - + txt += bullet + _("Snapshots are created and restored instantly. Snapshot creation is an atomic transaction at the file system level.") + "\n\n"; txt += bullet + _("Snapshots are restored by replacing system subvolumes. Since files are never copied, deleted or overwritten, there is no risk of data loss. The existing system is preserved as a new snapshot after restore.") + "\n\n"; - + txt += bullet + _("Snapshots are perfect, byte-for-byte copies of the system. Nothing is excluded.") + "\n\n"; txt += bullet + _("Snapshots are saved on the same disk from which they are created (system disk). Storage on other disks is not supported. If system disk fails then snapshots stored on it will be lost along with the system.") + "\n\n"; @@ -178,14 +178,14 @@ class SnapshotBackendBox : Gtk.Box{ txt += bullet + _("Size of BTRFS snapshots are initially zero. As system files gradually change with time, data gets written to new data blocks which take up disk space (copy-on-write). Files in the snapshot continue to point to original data blocks.") + "\n\n"; txt += bullet + _("OS must be installed on a BTRFS partition with Ubuntu-type subvolume layout (@ and @home subvolumes). Other layouts are not supported.") + "\n\n"; - + lbl_description.label = txt; } else{ string txt = "" + _("RSYNC Snapshots") + "\n\n"; txt += bullet + _("Snapshots are created by creating copies of system files using rsync, and hard-linking unchanged files from previous snapshot.") + "\n\n"; - + txt += bullet + _("All files are copied when first snapshot is created. Subsequent snapshots are incremental. Unchanged files will be hard-linked from the previous snapshot if available.") + "\n\n"; txt += bullet + _("Snapshots can be saved to any disk formatted with a Linux file system. Saving snapshots to non-system or external disk allows the system to be restored even if system disk is damaged or re-formatted.") + "\n\n"; @@ -195,14 +195,14 @@ class SnapshotBackendBox : Gtk.Box{ lbl_description.label = txt; } } - + public void init_backend(){ - + App.try_select_default_device_for_backup(parent_window); } public void refresh(){ - + opt_btrfs.active = App.btrfs_mode; type_changed(); update_description(); diff --git a/src/Gtk/SnapshotListBox.vala b/src/Gtk/SnapshotListBox.vala index d724334..4cef400 100644 --- a/src/Gtk/SnapshotListBox.vala +++ b/src/Gtk/SnapshotListBox.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class SnapshotListBox : Gtk.Box{ - + public Gtk.TreeView treeview; private Gtk.TreeViewColumn col_date; private Gtk.TreeViewColumn col_tags; @@ -50,7 +50,7 @@ class SnapshotListBox : Gtk.Box{ private Gtk.ImageMenuItem mi_mark; private Gtk.ImageMenuItem mi_view_log_create; private Gtk.ImageMenuItem mi_view_log_restore; - + private Gtk.Window parent_window; public signal void delete_selected(); @@ -61,21 +61,21 @@ class SnapshotListBox : Gtk.Box{ public SnapshotListBox (Gtk.Window _parent_window) { log_debug("SnapshotListBox: SnapshotListBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; margin = 6; init_treeview(); - + init_list_view_context_menu(); log_debug("SnapshotListBox: SnapshotListBox(): exit"); } private void init_treeview(){ - + //treeview treeview = new TreeView(); treeview.get_selection().mode = SelectionMode.MULTIPLE; @@ -182,7 +182,7 @@ class SnapshotListBox : Gtk.Box{ col.set_cell_data_func (cell_size, cell_size_render); col_size = col; treeview.append_column(col_size); - + col_size.clicked.connect(() => { if(treeview_sort_column_index == 2){ treeview_sort_column_desc = !treeview_sort_column_desc; @@ -207,7 +207,7 @@ class SnapshotListBox : Gtk.Box{ col.set_cell_data_func (cell_unshared, cell_unshared_render); col_unshared = col; treeview.append_column(col_unshared); - + col_unshared.clicked.connect(() => { if(treeview_sort_column_index == 2){ treeview_sort_column_desc = !treeview_sort_column_desc; @@ -230,7 +230,7 @@ class SnapshotListBox : Gtk.Box{ col_desc.pack_start (cell_desc, false); col_desc.set_cell_data_func (cell_desc, cell_desc_render); treeview.append_column(col_desc); - + cell_desc.editable = true; cell_desc.edited.connect ((path, new_text)=>{ Snapshot bak; @@ -247,22 +247,22 @@ class SnapshotListBox : Gtk.Box{ cell_text.width = 20; col_buffer.pack_start (cell_text, false); treeview.append_column(col_buffer); - + //tooltips treeview.query_tooltip.connect ((x, y, keyboard_tooltip, tooltip) => { - + TreeModel model; TreePath path; TreeIter iter; TreeViewColumn column; - + if (treeview.get_tooltip_context (ref x, ref y, keyboard_tooltip, out model, out path, out iter)){ - + int bx, by; treeview.convert_widget_to_bin_window_coords(x, y, out bx, out by); - + if (treeview.get_path_at_pos (bx, by, null, out column, null, null)){ - + if ((column == col_date) || (column == col_system)){ Snapshot bak; @@ -273,7 +273,7 @@ class SnapshotListBox : Gtk.Box{ if (App.btrfs_mode){ txt += "%s: %d\n".printf(_("Subvolumes"), bak.subvolumes.values.size); - + foreach(var subvol in bak.subvolumes_sorted){ if (txt.length > 0) { txt += "\n"; } txt += "%s".printf(subvol.path); @@ -282,7 +282,7 @@ class SnapshotListBox : Gtk.Box{ else{ txt = bak.path; } - + tooltip.set_markup(txt); return true; } @@ -311,7 +311,7 @@ class SnapshotListBox : Gtk.Box{ } private void init_list_view_context_menu(){ - + Gdk.RGBA gray = Gdk.RGBA(); gray.parse ("rgba(200,200,200,1)"); @@ -324,68 +324,68 @@ class SnapshotListBox : Gtk.Box{ item.activate.connect(()=> { delete_selected(); }); menu_snapshots.append(item); mi_remove = item; - + // mi_mark item = new ImageMenuItem.with_label(_("Mark/Unmark for Deletion")); item.image = IconManager.lookup_image("edit-delete", 16); item.activate.connect(()=> { mark_selected(); }); menu_snapshots.append(item); mi_mark = item; - + // mi_browse item = new ImageMenuItem.with_label(_("Browse Files")); item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_DIRECTORY, 16); item.activate.connect(()=> { browse_selected(); }); menu_snapshots.append(item); mi_browse = item; - + // mi_view_log_create item = new ImageMenuItem.with_label(_("View Rsync Log for Create")); item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_FILE, 16); item.activate.connect(()=> { view_snapshot_log(false); }); menu_snapshots.append(item); mi_view_log_create = item; - + // mi_view_log_restore item = new ImageMenuItem.with_label(_("View Rsync Log for Restore")); item.image = IconManager.lookup_image(IconManager.GENERIC_ICON_FILE, 16); item.activate.connect(()=> { view_snapshot_log(true); }); menu_snapshots.append(item); mi_view_log_restore = item; - + menu_snapshots.show_all(); // connect signal for shift+F10 treeview.popup_menu.connect(treeview_popup_menu); - + // connect signal for right-click treeview.button_press_event.connect(treeview_button_press_event); } // signals - + private bool treeview_popup_menu(){ - + return menu_snapshots_popup (menu_snapshots, null); } private bool treeview_button_press_event(Gdk.EventButton event){ - + if (event.button == 3) { return menu_snapshots_popup (menu_snapshots, event); } return false; } - + // renderers - + private void cell_date_render( CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + Snapshot bak; model.get (iter, 0, out bak, -1); - + var ctxt = (cell as Gtk.CellRendererText); ctxt.text = bak.date_formatted; ctxt.sensitive = !bak.marked_for_deletion; @@ -396,16 +396,16 @@ class SnapshotListBox : Gtk.Box{ else{ ctxt.markup = ctxt.text; } - + // Note: Avoid AM/PM as it may be hidden due to locale settings } private void cell_tags_render( CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + Snapshot bak; model.get (iter, 0, out bak, -1); - + var ctxt = (cell as Gtk.CellRendererText); ctxt.text = bak.taglist_short; ctxt.sensitive = !bak.marked_for_deletion; @@ -420,30 +420,30 @@ class SnapshotListBox : Gtk.Box{ private void cell_size_render( CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + Snapshot bak; model.get (iter, 0, out bak, -1); - + var ctxt = (cell as Gtk.CellRendererText); if (bak.btrfs_mode){ - + int64 size = 0; - + if (bak.subvolumes.has_key("@")){ size += bak.subvolumes["@"].total_bytes; } - + if (bak.subvolumes.has_key("@home")){ size += bak.subvolumes["@home"].total_bytes; } - + ctxt.text = format_file_size(size); } else{ ctxt.text = ""; } - + ctxt.sensitive = !bak.marked_for_deletion; if (bak.live){ @@ -456,29 +456,29 @@ class SnapshotListBox : Gtk.Box{ private void cell_unshared_render( CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + Snapshot bak; model.get (iter, 0, out bak, -1); - + var ctxt = (cell as Gtk.CellRendererText); if (bak.btrfs_mode){ - + int64 size = 0; - + if (bak.subvolumes.has_key("@")){ size += bak.subvolumes["@"].unshared_bytes; } if (bak.subvolumes.has_key("@home")){ size += bak.subvolumes["@home"].unshared_bytes; } - + ctxt.text = format_file_size(size); } else{ ctxt.text = ""; } - + ctxt.sensitive = !bak.marked_for_deletion; if (bak.live){ @@ -491,10 +491,10 @@ class SnapshotListBox : Gtk.Box{ private void cell_system_render( CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ - + Snapshot bak; model.get (iter, 0, out bak, -1); - + var ctxt = (cell as Gtk.CellRendererText); ctxt.text = bak.sys_distro; ctxt.sensitive = !bak.marked_for_deletion; @@ -528,9 +528,9 @@ class SnapshotListBox : Gtk.Box{ } private bool menu_snapshots_popup (Gtk.Menu popup, Gdk.EventButton? event) { - + var selected = selected_snapshots(); - + mi_remove.sensitive = (selected.size > 0); mi_mark.sensitive = (selected.size > 0); mi_view_log_create.sensitive = !App.btrfs_mode; @@ -539,7 +539,7 @@ class SnapshotListBox : Gtk.Box{ if (!App.btrfs_mode){ if (selected.size > 0){ - + mi_view_log_restore.sensitive = file_exists(selected[0].rsync_restore_log_file) || file_exists(selected[0].rsync_restore_changes_log_file); } @@ -550,12 +550,12 @@ class SnapshotListBox : Gtk.Box{ } else { menu_snapshots.popup (null, null, null, 0, Gtk.get_current_event_time()); } - + return true; } // actions - + public void refresh(){ var model = new Gtk.ListStore(1, typeof(Snapshot)); @@ -566,7 +566,7 @@ class SnapshotListBox : Gtk.Box{ } App.repo.load_snapshots(); - + var list = App.repo.snapshots; if (treeview_sort_column_index == 0){ @@ -616,23 +616,23 @@ class SnapshotListBox : Gtk.Box{ } col_size.visible = App.btrfs_mode; - col_unshared.visible = App.btrfs_mode; + col_unshared.visible = App.btrfs_mode; treeview.set_model (model); treeview.columns_autosize (); } public void hide_context_menu(){ - + // disconnect signal for shift+F10 treeview.popup_menu.disconnect(treeview_popup_menu); - + // disconnect signal for right-click treeview.button_press_event.disconnect(treeview_button_press_event); } public Gee.ArrayList selected_snapshots(){ - + var list = new Gee.ArrayList(); TreeIter iter; diff --git a/src/Gtk/UsersBox.vala b/src/Gtk/UsersBox.vala index b8a8bbf..dbcc719 100644 --- a/src/Gtk/UsersBox.vala +++ b/src/Gtk/UsersBox.vala @@ -33,7 +33,7 @@ using TeeJee.System; using TeeJee.Misc; class UsersBox : Gtk.Box{ - + private Gtk.TreeView treeview; private Gtk.ScrolledWindow scrolled_treeview; private Gtk.Window parent_window; @@ -43,11 +43,11 @@ class UsersBox : Gtk.Box{ private Gtk.CheckButton chk_include_btrfs_home; private Gtk.CheckButton chk_enable_qgroups; private bool restore_mode = false; - + public UsersBox (Gtk.Window _parent_window, ExcludeBox _exclude_box, bool _restore_mode) { log_debug("UsersBox: UsersBox()"); - + //base(Gtk.Orientation.VERTICAL, 6); // issue with vala GLib.Object(orientation: Gtk.Orientation.VERTICAL, spacing: 6); // work-around parent_window = _parent_window; @@ -59,11 +59,11 @@ class UsersBox : Gtk.Box{ var box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6); add(box); - + add_label_header(this, _("User Home Directories"), true); // ------------------------ - + var label = add_label(this, _("User home directories are excluded by default unless you enable them here"), false, true); lbl_message = label; @@ -75,14 +75,14 @@ class UsersBox : Gtk.Box{ init_btrfs_home_option(box_btrfs); init_btrfs_qgroup_option(box_btrfs); - + refresh(); log_debug("UsersBox: UsersBox(): exit"); } private void init_treeview(){ - + // treeview treeview = new TreeView(); treeview.get_selection().mode = SelectionMode.MULTIPLE; @@ -99,7 +99,7 @@ class UsersBox : Gtk.Box{ scrolled.expand = true; add(scrolled); scrolled_treeview = scrolled; - + // column var col = new TreeViewColumn(); col.title = _("User"); @@ -108,7 +108,7 @@ class UsersBox : Gtk.Box{ // name var cell_text = new CellRendererText (); col.pack_start (cell_text, false); - + col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{ SystemUser user; model.get(iter, 0, out user); @@ -123,7 +123,7 @@ class UsersBox : Gtk.Box{ // name cell_text = new CellRendererText (); col.pack_start (cell_text, false); - + col.set_cell_data_func (cell_text, (cell_layout, cell, model, iter)=>{ SystemUser user; model.get(iter, 0, out user); @@ -131,11 +131,11 @@ class UsersBox : Gtk.Box{ }); // column ------------------------------------------------- - + col = new TreeViewColumn(); col.title = _("Exclude All Files"); treeview.append_column(col); - + // radio_exclude var cell_radio = new Gtk.CellRendererToggle(); cell_radio.radio = true; @@ -144,19 +144,19 @@ class UsersBox : Gtk.Box{ col.pack_start (cell_radio, false); col.set_attributes(cell_radio, "active", 3); - + cell_radio.toggled.connect((cell, path)=>{ log_debug("cell_exclude.toggled()"); - + var model = (Gtk.ListStore) treeview.model; TreeIter iter; - + model.get_iter_from_string (out iter, path); bool enabled; model.get(iter, 3, out enabled); - + SystemUser user; model.get(iter, 0, out user); @@ -168,9 +168,9 @@ class UsersBox : Gtk.Box{ inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name); exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name); } - + enabled = !enabled; - + if (enabled){ if (!App.exclude_list_user.contains(exc_pattern)){ App.exclude_list_user.add(exc_pattern); @@ -184,16 +184,16 @@ class UsersBox : Gtk.Box{ } this.refresh_treeview(); - + //exclude_box.refresh_treeview(); }); // column ------------------------------------------------- - + col = new TreeViewColumn(); col.title = _("Include Only Hidden Files"); treeview.append_column(col); - + // radio_include cell_radio = new Gtk.CellRendererToggle(); cell_radio.radio = true; @@ -202,41 +202,41 @@ class UsersBox : Gtk.Box{ col.pack_start (cell_radio, false); col.set_attributes(cell_radio, "active", 1); - + cell_radio.toggled.connect((cell, path)=>{ log_debug("cell_include.toggled()"); - + var model = (Gtk.ListStore) treeview.model; TreeIter iter; - + model.get_iter_from_string (out iter, path); bool enabled; model.get(iter, 1, out enabled); - + SystemUser user; model.get(iter, 0, out user); string exc_pattern = "%s/**".printf(user.home_path); string inc_pattern = "+ %s/**".printf(user.home_path); string inc_hidden_pattern = "+ %s/.**".printf(user.home_path); - + if (user.has_encrypted_home){ inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name); exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name); } - + enabled = !enabled; - + if (enabled){ - + if (user.has_encrypted_home){ - + string txt = _("Encrypted Home Directory"); string msg = _("Selected user has an encrypted home directory. It's not possible to include only hidden files."); - + gtk_messagebox(txt, msg, parent_window, true); return; @@ -261,7 +261,7 @@ class UsersBox : Gtk.Box{ }); // column -------------------------------------------- - + col = new TreeViewColumn(); col.title = _("Include All Files"); treeview.append_column(col); @@ -272,7 +272,7 @@ class UsersBox : Gtk.Box{ cell_radio.xpad = 2; cell_radio.activatable = true; col.pack_start (cell_radio, false); - + col.set_attributes(cell_radio, "active", 2); cell_radio.toggled.connect((cell, path)=>{ @@ -297,7 +297,7 @@ class UsersBox : Gtk.Box{ inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name); exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name); } - + if (enabled){ if (!App.exclude_list_user.contains(inc_pattern)){ App.exclude_list_user.add(inc_pattern); @@ -325,24 +325,24 @@ class UsersBox : Gtk.Box{ private void init_btrfs_home_option(Gtk.Box box){ if (restore_mode){ - + chk_include_btrfs_home = new Gtk.CheckButton.with_label(_("Restore @home subvolume")); box.add(chk_include_btrfs_home); chk_include_btrfs_home.toggled.connect(()=>{ - App.include_btrfs_home_for_restore = chk_include_btrfs_home.active; + App.include_btrfs_home_for_restore = chk_include_btrfs_home.active; }); - + } else { chk_include_btrfs_home = new Gtk.CheckButton.with_label(_("Include @home subvolume in backups")); - + box.add(chk_include_btrfs_home); chk_include_btrfs_home.toggled.connect(()=>{ - App.include_btrfs_home_for_backup = chk_include_btrfs_home.active; + App.include_btrfs_home_for_backup = chk_include_btrfs_home.active; }); } } @@ -353,7 +353,7 @@ class UsersBox : Gtk.Box{ var label = add_label_header(box, _("Miscellaneous"), true); label.margin_top = 12; - + chk_enable_qgroups = new Gtk.CheckButton.with_label(_("Enable BTRFS qgroups (recommended)")); box.add(chk_enable_qgroups); @@ -362,11 +362,11 @@ class UsersBox : Gtk.Box{ chk_enable_qgroups.active = App.btrfs_use_qgroup; chk_enable_qgroups.toggled.connect(()=>{ - App.btrfs_use_qgroup = chk_enable_qgroups.active; + App.btrfs_use_qgroup = chk_enable_qgroups.active; }); } } - + // helpers public void refresh(){ @@ -381,7 +381,7 @@ class UsersBox : Gtk.Box{ box_btrfs.set_no_show_all(false); box_btrfs.show_all(); - + if (restore_mode){ chk_include_btrfs_home.active = App.include_btrfs_home_for_restore; } @@ -397,21 +397,21 @@ class UsersBox : Gtk.Box{ scrolled_treeview.set_no_show_all(false); refresh_treeview(); - + box_btrfs.hide(); box_btrfs.set_no_show_all(true); } show_all(); } - + private void refresh_treeview(){ - + var model = new Gtk.ListStore(4, typeof(SystemUser), typeof(bool), typeof(bool), typeof(bool)); treeview.model = model; TreeIter iter; - + foreach(var user in App.current_system_users.values){ if (user.is_system){ continue; } @@ -424,13 +424,13 @@ class UsersBox : Gtk.Box{ inc_pattern = "+ /home/.ecryptfs/%s/***".printf(user.name); exc_pattern = "/home/.ecryptfs/%s/***".printf(user.name); } - + bool include_hidden = App.exclude_list_user.contains(inc_hidden_pattern); bool include_all = App.exclude_list_user.contains(inc_pattern); bool exclude_all = !include_hidden && !include_all; //App.exclude_list_user.contains(exc_pattern); if (exclude_all){ - + if (!App.exclude_list_user.contains(exc_pattern)){ App.exclude_list_user.add(exc_pattern); } @@ -441,7 +441,7 @@ class UsersBox : Gtk.Box{ App.exclude_list_user.remove(inc_hidden_pattern); } } - + model.append(out iter); model.set (iter, 0, user); model.set (iter, 1, include_hidden); @@ -467,10 +467,10 @@ class UsersBox : Gtk.Box{ if (!App.exclude_list_user.contains(pattern) && !App.exclude_list_default.contains(pattern) && !App.exclude_list_home.contains(pattern)){ - + App.exclude_list_user.add(pattern); } - + iterExists = store.iter_next(ref iter); }*/ diff --git a/src/Utility/AppLock.vala b/src/Utility/AppLock.vala index eba91bf..c1f509e 100644 --- a/src/Utility/AppLock.vala +++ b/src/Utility/AppLock.vala @@ -20,22 +20,22 @@ * * */ - + using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.ProcessHelper; using TeeJee.Misc; - + public class AppLock : GLib.Object { public string lock_file = ""; public string lock_message = ""; - + public bool create(string app_name, string message){ var lock_dir = "/var/run/lock/%s".printf(app_name); dir_create(lock_dir); lock_file = path_combine(lock_dir, "lock"); - + try{ var file = File.new_for_path(lock_file); if (file.query_exists()) { @@ -72,7 +72,7 @@ public class AppLock : GLib.Object { string current_pid = ((long) Posix.getpid()).to_string(); file_write(lock_file, "%s;%s".printf(current_pid, message)); } - + public void remove(){ try{ var file = File.new_for_path (lock_file); diff --git a/src/Utility/AsyncTask.vala b/src/Utility/AsyncTask.vala index 3d6357a..b26cbbe 100644 --- a/src/Utility/AsyncTask.vala +++ b/src/Utility/AsyncTask.vala @@ -29,7 +29,7 @@ using TeeJee.System; using TeeJee.Misc; public abstract class AsyncTask : GLib.Object{ - + private string err_line = ""; private string out_line = ""; private DataOutputStream dos_in; @@ -40,7 +40,7 @@ public abstract class AsyncTask : GLib.Object{ private bool stdout_is_open = false; private bool stderr_is_open = false; - + protected Pid child_pid; private int input_fd; private int output_fd; @@ -52,7 +52,7 @@ public abstract class AsyncTask : GLib.Object{ protected string log_file = ""; public bool background_mode = false; - + // public public AppStatus status; public string status_line = ""; @@ -67,40 +67,40 @@ public abstract class AsyncTask : GLib.Object{ public int64 prg_bytes_total = 0; public string eta = ""; //public bool is_running = false; - + // signals public signal void stdout_line_read(string line); public signal void stderr_line_read(string line); public signal void task_complete(); protected AsyncTask(){ - + working_dir = TEMP_DIR + "/" + timestamp_for_path(); script_file = path_combine(working_dir, "script.sh"); log_file = path_combine(working_dir, "task.log"); //regex = new Gee.HashMap(); // needs to be initialized again in instance constructor - + dir_create(working_dir); } - + public bool begin(){ status = AppStatus.RUNNING; - + bool has_started = true; is_terminated = false; finish_called = false; - + prg_count = 0; prg_bytes = 0; error_msg = ""; - + string[] spawn_args = new string[1]; spawn_args[0] = script_file; - + string[] spawn_env = Environ.get(); - + try { // start timer timer = new GLib.Timer(); @@ -121,7 +121,7 @@ public abstract class AsyncTask : GLib.Object{ set_priority(); log_debug("AsyncTask: child_pid: %d".printf(child_pid)); - + // create stream readers UnixOutputStream uos_in = new UnixOutputStream(input_fd, false); UnixInputStream uis_out = new UnixInputStream(output_fd, false); @@ -171,7 +171,7 @@ public abstract class AsyncTask : GLib.Object{ private void read_stdout() { try { stdout_is_open = true; - + out_line = dis_out.read_line (null); while (out_line != null) { //log_msg("O: " + out_line); @@ -202,16 +202,16 @@ public abstract class AsyncTask : GLib.Object{ log_error (e.message); } } - + private void read_stderr() { try { stderr_is_open = true; - + err_line = dis_err.read_line (null); while (err_line != null) { if (!is_terminated && (err_line.length > 0)){ error_msg += "%s\n".printf(err_line); - + parse_stderr_line(err_line); stderr_line_read(err_line); //signal } @@ -222,7 +222,7 @@ public abstract class AsyncTask : GLib.Object{ // dispose stderr if ((dis_err != null) && !dis_err.is_closed()){ - dis_err.close(); + dis_err.close(); } //dis_err.close(); dis_err = null; @@ -253,19 +253,19 @@ public abstract class AsyncTask : GLib.Object{ log_error (e.message); } } - + protected abstract void parse_stdout_line(string out_line); - + protected abstract void parse_stderr_line(string err_line); - + private void finish(){ - + // finish() gets called by 2 threads but should be executed only once if (finish_called) { return; } finish_called = true; - + log_debug("AsyncTask: finish(): enter"); - + // dispose stdin try{ if ((dos_in != null) && !dos_in.is_closed() && !dos_in.is_closing()){ @@ -277,7 +277,7 @@ public abstract class AsyncTask : GLib.Object{ //log_error ("AsyncTask.finish(): dos_in.close()"); //log_error (e.message); } - + dos_in = null; GLib.FileUtils.close(input_fd); @@ -298,13 +298,13 @@ public abstract class AsyncTask : GLib.Object{ } read_exit_code(); - + status_line = ""; err_line = ""; out_line = ""; timer.stop(); - + finish_task(); if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { @@ -312,14 +312,14 @@ public abstract class AsyncTask : GLib.Object{ } //dir_delete(working_dir); - + task_complete(); //signal } protected abstract void finish_task(); protected int read_exit_code(){ - + exit_code = -1; var path = file_parent(script_file) + "/status"; if (file_exists(path)){ @@ -331,14 +331,14 @@ public abstract class AsyncTask : GLib.Object{ } public bool is_running(){ - + return (status == AppStatus.RUNNING); } - + // public actions -------------- public void pause() { - + Pid sub_child_pid; foreach (long pid in get_process_children(child_pid)) { sub_child_pid = (Pid) pid; @@ -349,7 +349,7 @@ public abstract class AsyncTask : GLib.Object{ } public void resume() { - + Pid sub_child_pid; foreach (long pid in get_process_children(child_pid)) { sub_child_pid = (Pid) pid; @@ -360,21 +360,21 @@ public abstract class AsyncTask : GLib.Object{ } public void stop(AppStatus status_to_update = AppStatus.CANCELLED) { - + // we need to un-freeze the processes before we kill them if (status == AppStatus.PAUSED) { resume(); } status = status_to_update; - + process_quit(child_pid); - + log_debug("process_quit: %d".printf(child_pid)); } public void set_priority() { - + if (background_mode){ set_priority_value(5); } @@ -384,7 +384,7 @@ public abstract class AsyncTask : GLib.Object{ } public void set_priority_value(int prio) { - + Pid app_pid = Posix.getpid(); process_set_priority (app_pid, prio); @@ -423,7 +423,7 @@ public abstract class AsyncTask : GLib.Object{ } public void print_app_status(){ - + switch(status){ case AppStatus.NOT_STARTED: log_debug("status=%s".printf("NOT_STARTED")); @@ -465,13 +465,13 @@ public class RsyncTask : AsyncTask{ public string source_path = ""; public string dest_path = ""; public bool verbose = true; - + public RsyncTask(string _script_file, string _working_dir, string _log_file){ working_dir = _working_dir; script_file = _script_file; log_file = _log_file; } - + public void prepare() { string script_text = build_script(); save_bash_script_temp(script_text, script_file); @@ -504,18 +504,18 @@ public class RsyncTask : AsyncTask{ } source_path = remove_trailing_slash(source_path); - + dest_path = remove_trailing_slash(dest_path); - + cmd += " '%s/'".printf(escape_single_quote(source_path)); cmd += " '%s/'".printf(escape_single_quote(dest_path)); - + //cmd += " /. \"%s\"".printf(sync_path + "/localhost/"); return script.str; } - + // execution ---------------------------- public void execute() { @@ -525,8 +525,8 @@ public class RsyncTask : AsyncTask{ begin(); if (status == AppStatus.RUNNING){ - - + + } } @@ -534,15 +534,15 @@ public class RsyncTask : AsyncTask{ if (is_terminated) { return; } - + update_progress_parse_console_output(out_line); } - + public override void parse_stderr_line(string err_line){ if (is_terminated) { return; } - + update_progress_parse_console_output(err_line); } diff --git a/src/Utility/CronTab.vala b/src/Utility/CronTab.vala index 6789ebf..282a92c 100644 --- a/src/Utility/CronTab.vala +++ b/src/Utility/CronTab.vala @@ -20,7 +20,7 @@ * * */ - + using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.ProcessHelper; @@ -33,7 +33,7 @@ public class CronTab : GLib.Object { public static void clear_cached_text(){ crontab_text = null; } - + public static string crontab_read_all(string user_name = ""){ string std_out, std_err; @@ -43,9 +43,9 @@ public class CronTab : GLib.Object { } log_debug(cmd); - + int ret_val = exec_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ log_debug(_("Failed to read cron tab")); return ""; @@ -56,7 +56,7 @@ public class CronTab : GLib.Object { } public static bool has_job(string entry, bool partial_match, bool use_cached_text){ - + // read crontab file string tab = ""; if (use_cached_text && (crontab_text != null)){ @@ -84,9 +84,9 @@ public class CronTab : GLib.Object { return false; } - + public static bool add_job(string entry, bool use_cached_text){ - + // read crontab file string tab = ""; if (use_cached_text && (crontab_text != null)){ @@ -96,7 +96,7 @@ public class CronTab : GLib.Object { crontab_text = crontab_read_all(); tab = crontab_text; } - + var lines = new Gee.ArrayList(); foreach(string line in tab.split("\n")){ lines.add(line); @@ -139,7 +139,7 @@ public class CronTab : GLib.Object { } public static bool remove_job(string entry, bool use_regex, bool use_cached_text){ - + // read crontab file string tab = ""; if (use_cached_text && (crontab_text != null)){ @@ -149,12 +149,12 @@ public class CronTab : GLib.Object { crontab_text = crontab_read_all(); tab = crontab_text; } - + var lines = new Gee.ArrayList(); foreach(string line in tab.split("\n")){ lines.add(line); } - + Regex regex = null; if (use_regex){ @@ -175,7 +175,7 @@ public class CronTab : GLib.Object { } if (use_regex && (regex != null)){ - + MatchInfo match; if (regex.match(line, 0, out match)) { lines.remove(line); @@ -225,7 +225,7 @@ public class CronTab : GLib.Object { log_error(_("File not found") + ": %s".printf(file_path)); return false; } - + var cmd = "crontab"; if (user_name.length > 0){ cmd += " -u %s".printf(user_name); @@ -245,12 +245,12 @@ public class CronTab : GLib.Object { return true; } } - + public static bool export(string file_path, string user_name = ""){ if (file_exists(file_path)){ file_delete(file_path); } - + bool ok = file_write(file_path, crontab_read_all(user_name)); if (!ok){ @@ -268,11 +268,11 @@ public class CronTab : GLib.Object { } public static bool add_script_file(string file_name, string cron_dir_type, string text, bool stop_cron_emails){ - + /* Note: * cron.d and cron.hourly are managed by cron so it expects entries in crontab format * minute hour day_of_month month day_of_week user command - * + * * cron.{daily|weekly|monthly} are read by anacron. scripts placed here should have commands only. * */ @@ -310,7 +310,7 @@ public class CronTab : GLib.Object { chmod(file_path, "644"); log_msg(_("Added cron task") + ": %s".printf(file_path)); - + return true; } @@ -334,11 +334,11 @@ public class CronTab : GLib.Object { if (!file_exists(file_path)){ return true; } - + file_delete(file_path); log_msg(_("Removed cron task") + ": %s".printf(file_path)); - + return true; } } diff --git a/src/Utility/CryptTabEntry.vala b/src/Utility/CryptTabEntry.vala index 86c1e62..81b0abc 100644 --- a/src/Utility/CryptTabEntry.vala +++ b/src/Utility/CryptTabEntry.vala @@ -31,7 +31,7 @@ using TeeJee.System; using TeeJee.Misc; public class CryptTabEntry : GLib.Object{ - + public bool is_comment = false; public bool is_empty_line = false; @@ -57,7 +57,7 @@ public class CryptTabEntry : GLib.Object{ } public static Gee.ArrayList read_file(string file_path){ - + var list = new Gee.ArrayList(); if (!file_exists(file_path)){ return list; } @@ -106,7 +106,7 @@ public class CryptTabEntry : GLib.Object{ } public static string write_file(Gee.ArrayList entries, string file_path, bool keep_comments_and_empty_lines = true){ - + string text = ""; foreach(var entry in entries){ if (entry.is_comment || entry.is_empty_line){ @@ -124,29 +124,29 @@ public class CryptTabEntry : GLib.Object{ if (file_exists(file_path)){ file_delete(file_path); } - + file_write(file_path, text); - + return text; } public void append_option(string option){ - + if (!options.contains(option)){ options += ",%s".printf(option); } - + if(options.has_prefix(",")){ options = options[1:options.length]; } - + options = options.strip(); } public void remove_option(string option){ - + options = options.replace(option,"").strip(); - + if(options.has_prefix(",")){ options = options[1:options.length]; } @@ -160,13 +160,13 @@ public class CryptTabEntry : GLib.Object{ public static CryptTabEntry? find_entry_by_uuid( Gee.ArrayList entries, string uuid){ - + foreach(var entry in entries){ if (entry.device_uuid == uuid){ return entry; } } - + return null; } } diff --git a/src/Utility/DeleteFileTask.vala b/src/Utility/DeleteFileTask.vala index ccb9950..f0fdfd5 100644 --- a/src/Utility/DeleteFileTask.vala +++ b/src/Utility/DeleteFileTask.vala @@ -37,17 +37,17 @@ public class DeleteFileTask : AsyncTask{ public bool use_rsync = false; //private - private string source_path = ""; - + private string source_path = ""; + // regex private Gee.HashMap regex_list; - + // status public int64 status_line_count = 0; public int64 total_size = 0; public string status_message = ""; public string time_remaining = ""; - + public DeleteFileTask(){ init_regular_expressions(); } @@ -56,9 +56,9 @@ public class DeleteFileTask : AsyncTask{ if (regex_list != null){ return; // already initialized } - + regex_list = new Gee.HashMap(); - + try { regex_list["rsync-deleted"] = new Regex( @@ -69,7 +69,7 @@ public class DeleteFileTask : AsyncTask{ log_error (e.message); } } - + public void prepare() { string script_text = build_script(); log_debug(script_text); @@ -108,7 +108,7 @@ public class DeleteFileTask : AsyncTask{ source_path = remove_trailing_slash(source_path); dest_path = remove_trailing_slash(dest_path); - + cmd += " '%s/'".printf(escape_single_quote(source_path)); cmd += " '%s/'".printf(escape_single_quote(dest_path)); } @@ -133,16 +133,16 @@ public class DeleteFileTask : AsyncTask{ public void execute() { status = AppStatus.RUNNING; - + log_debug("RsyncTask:execute()"); - + prepare(); begin(); if (status == AppStatus.RUNNING){ - - + + } } @@ -150,15 +150,15 @@ public class DeleteFileTask : AsyncTask{ if (is_terminated) { return; } - + update_progress_parse_console_output(out_line); } - + public override void parse_stderr_line(string err_line){ if (is_terminated) { return; } - + update_progress_parse_console_output(err_line); } @@ -173,16 +173,16 @@ public class DeleteFileTask : AsyncTask{ prg_count = status_line_count; progress = (prg_count * 1.0) / prg_count_total; } - + MatchInfo match; if (regex_list["rsync-deleted"].match(line, 0, out match)) { - + //log_debug("matched: rsync-deleted:%s".printf(line)); status_line = match.fetch(1).split(" -> ")[0].strip(); } else { - + //log_debug("matched: else:%s".printf(line)); status_line = line.strip(); diff --git a/src/Utility/Device.vala b/src/Utility/Device.vala index c55f8f6..d94eb97 100755 --- a/src/Utility/Device.vala +++ b/src/Utility/Device.vala @@ -21,7 +21,7 @@ * * */ - + /* Functions and classes for handling disk partitions */ using TeeJee.Logging; @@ -40,7 +40,7 @@ public class Device : GLib.Object{ public static double KiB = 1024; public static double MiB = 1024 * KiB; public static double GiB = 1024 * MiB; - + public string device = ""; public string name = ""; public string kname = ""; @@ -51,7 +51,7 @@ public class Device : GLib.Object{ public string label = ""; public string partuuid = ""; public string partlabel = ""; - + public int major = -1; public int minor = -1; @@ -73,11 +73,11 @@ public class Device : GLib.Object{ public bool removable = false; public bool read_only = false; - + public uint64 size_bytes = 0; public uint64 used_bytes = 0; public uint64 available_bytes = 0; - + public string used_percent = ""; public string dist_info = ""; public Gee.ArrayList mount_points; @@ -88,7 +88,7 @@ public class Device : GLib.Object{ private static string lsblk_version = ""; private static bool lsblk_is_ancient = false; - + private static Gee.ArrayList device_list; public Device(){ @@ -116,7 +116,7 @@ public class Device : GLib.Object{ lsblk_is_ancient = true; } } - + public uint64 free_bytes{ get{ return (used_bytes == 0) ? 0 : (size_bytes - used_bytes); @@ -130,7 +130,7 @@ public class Device : GLib.Object{ } else if (size_bytes > 0){ return "%.1f GB".printf(size_bytes / GB); - } + } else{ return ""; } @@ -156,7 +156,7 @@ public class Device : GLib.Object{ } public bool is_mounted_at_path(string subvolname, string mount_path){ - + foreach (var mnt in mount_points){ if (mnt.mount_point == mount_path){ if (subvolname.length == 0){ @@ -169,7 +169,7 @@ public class Device : GLib.Object{ } } } - + return false; } @@ -215,13 +215,13 @@ public class Device : GLib.Object{ } public Device? first_linux_child(){ - + foreach(var child in children){ if (child.has_linux_filesystem()){ return child; } } - + return null; } @@ -230,7 +230,7 @@ public class Device : GLib.Object{ } // static -------------------------------- - + public static Gee.ArrayList get_filesystems(bool get_space = true, bool get_mounts = true){ /* Returns list of block devices @@ -268,7 +268,7 @@ public class Device : GLib.Object{ //print_device_mounts(list); log_debug("Device: get_filesystems(): %d".printf(list.size)); - + return list; } @@ -298,7 +298,7 @@ public class Device : GLib.Object{ if (dev.pkname.length == 0){ return; } var top_kname = dev.pkname; - + foreach (var part in list){ if (part.kname == top_kname){ if (part.pkname.length > 0){ @@ -374,7 +374,7 @@ public class Device : GLib.Object{ public static Gee.ArrayList get_block_devices_using_lsblk(string dev_name = ""){ //log_debug("Device: get_block_devices_using_lsblk()"); - + /* Returns list of mounted partitions using 'lsblk' command Populates device, type, uuid, label */ @@ -439,10 +439,10 @@ public class Device : GLib.Object{ Device pi = new Device(); int pos = 0; - + pi.name = match.fetch(++pos).strip(); pi.kname = match.fetch(++pos).strip(); - + pi.label = match.fetch(++pos); // don't strip; labels can have leading or trailing spaces pi.uuid = match.fetch(++pos).strip(); @@ -470,12 +470,12 @@ public class Device : GLib.Object{ pi.major = int.parse(txt.split(":")[0]); pi.minor = int.parse(txt.split(":")[1]); } - + if (!lsblk_is_ancient){ - + pi.partlabel = match.fetch(++pos); // don't strip; labels can have leading or trailing spaces pi.partuuid = match.fetch(++pos).strip(); - + pi.pkname = match.fetch(++pos).strip(); pi.vendor = match.fetch(++pos).strip(); pi.serial = match.fetch(++pos).strip(); @@ -718,7 +718,7 @@ public class Device : GLib.Object{ if (LOG_DEBUG){ log_debug(cmd); } - + ret_val = exec_script_sync(cmd, out std_out, out std_err); if (ret_val != 0){ var msg = "blkid: " + _("Failed to get partition list"); @@ -793,7 +793,7 @@ public class Device : GLib.Object{ } log_debug("Device: get_block_devices_using_blkid(): %d".printf(list.size)); - + return list; } @@ -891,7 +891,7 @@ public class Device : GLib.Object{ // resolve device name -------------------- pi.device = resolve_device_name(pi.device); - + // get uuid --------------------------- pi.uuid = get_device_uuid(pi.device); @@ -902,7 +902,7 @@ public class Device : GLib.Object{ list.add(pi); } } - + log_debug("Device: get_disk_space_using_df(): %d".printf(list.size)); return list; @@ -1050,7 +1050,7 @@ public class Device : GLib.Object{ } log_debug("Device: get_mounted_filesystems_using_mtab(): %d".printf(list.size)); - + return list; } @@ -1067,18 +1067,18 @@ public class Device : GLib.Object{ } public static Device? get_device_by_path(string path_to_check){ - + var list = Device.get_disk_space_using_df(path_to_check); - + if (list.size > 0){ return list[0]; } - + return null; } - + public static string get_device_uuid(string device){ - + if (device_list == null){ device_list = get_block_devices_using_lsblk(); } @@ -1087,7 +1087,7 @@ public class Device : GLib.Object{ return dev.uuid; } } - + return ""; } @@ -1106,7 +1106,7 @@ public class Device : GLib.Object{ } var list_mtab = get_mounted_filesystems_using_mtab(); - + var dev = find_device_in_list(list_mtab, uuid); if (dev != null){ @@ -1155,20 +1155,20 @@ public class Device : GLib.Object{ public static Device? find_device_in_list(Gee.ArrayList list, string _dev_alias){ string dev_alias = _dev_alias; - + if (dev_alias.down().has_prefix("uuid=")){ - + dev_alias = dev_alias.split("=",2)[1].strip().down(); } else if (file_exists(dev_alias) && file_is_symlink(dev_alias)){ var link_path = file_get_symlink_target(dev_alias); - + dev_alias = link_path.replace("../../../","/dev/").replace("../../","/dev/").replace("../","/dev/"); } foreach(var dev in list){ - + if (dev.device == dev_alias){ return dev; } @@ -1206,9 +1206,9 @@ public class Device : GLib.Object{ return null; } - + public void copy_fields_from(Device dev2){ - + this.device = dev2.device; this.name = dev2.name; this.kname = dev2.kname; @@ -1216,14 +1216,14 @@ public class Device : GLib.Object{ this.label = dev2.label; this.uuid = dev2.uuid; this.mapped_name = dev2.mapped_name; - + this.type = dev2.type; this.fstype = dev2.fstype; this.size_bytes = dev2.size_bytes; this.used_bytes = dev2.used_bytes; this.available_bytes = dev2.available_bytes; - + this.mount_points = dev2.mount_points; this.symlinks = dev2.symlinks; this.parent = dev2.parent; @@ -1239,9 +1239,9 @@ public class Device : GLib.Object{ } public Device? query_changes(){ - + Device dev_new = null; - + foreach (var dev in get_block_devices_using_lsblk()){ if (uuid.length > 0){ if (dev.uuid == uuid){ @@ -1256,18 +1256,18 @@ public class Device : GLib.Object{ } } } - + return dev_new; } - + public void query_disk_space(){ /* Updates disk space info and returns the given Device object */ var list_df = get_disk_space_using_df(device); - + var dev_df = find_device_in_list(list_df, uuid); - + if (dev_df != null){ // update dev fields size_bytes = dev_df.size_bytes; @@ -1278,14 +1278,14 @@ public class Device : GLib.Object{ } // mounting --------------------------------- - + public static bool automount_udisks(string dev_name_or_uuid, Gtk.Window? parent_window){ - + if (dev_name_or_uuid.length == 0){ log_error(_("Device name is empty!")); return false; } - + var cmd = "udisksctl mount -b '%s'".printf(dev_name_or_uuid); log_debug(cmd); int status = Posix.system(cmd); @@ -1312,11 +1312,11 @@ public class Device : GLib.Object{ var cmd = "udisksctl loop-setup -r -f '%s'".printf( escape_single_quote(iso_file_path)); - + log_debug(cmd); string std_out, std_err; int exit_code = exec_sync(cmd, out std_out, out std_err); - + if (exit_code == 0){ log_msg("%s".printf(std_out)); //log_msg("%s".printf(std_err)); @@ -1328,7 +1328,7 @@ public class Device : GLib.Object{ loop_device = std_out.split(" as ")[1].replace(".","").strip(); log_msg("loop_device: %s".printf(loop_device)); - + var list = get_block_devices_using_lsblk(); foreach(var dev in list){ if ((dev.pkname == loop_device.replace("/dev/","")) && (dev.fstype == "iso9660")){ @@ -1337,7 +1337,7 @@ public class Device : GLib.Object{ } } } - + return false; } @@ -1347,7 +1347,7 @@ public class Device : GLib.Object{ log_error(_("Device name is empty!")); return false; } - + var cmd = "udisksctl unmount -b '%s'".printf(dev_name_or_uuid); log_debug(cmd); int status = Posix.system(cmd); @@ -1358,12 +1358,12 @@ public class Device : GLib.Object{ gtk_messagebox("Error", msg, parent_window, true); } } - + return (status == 0); } public static Device? luks_unlock( - Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window, + Device luks_device, string mapped_name, string passphrase, Gtk.Window? parent_window, out string message, out string details){ /* Unlocks a LUKS device using provided passphrase. @@ -1371,10 +1371,10 @@ public class Device : GLib.Object{ * Displays a GTK prompt if parent_window is not null * Otherwise prompts user on terminal with a timeout of 20 secsonds * */ - + Device unlocked_device = null; string std_out = "", std_err = ""; - + // check if not encrypted if (!luks_device.fstype.contains("luks") && !luks_device.fstype.contains("crypt")){ message = _("This device is not encrypted"); @@ -1389,7 +1389,7 @@ public class Device : GLib.Object{ unlocked_device = part; message = _("Device is unlocked"); details = _("Unlocked device is mapped to '%s'").printf(part.mapped_name); - return part; + return part; } } @@ -1403,11 +1403,11 @@ public class Device : GLib.Object{ if (parent_window == null){ // console mode - + if ((luks_pass == null) || (luks_pass.length == 0)){ // prompt user on terminal and unlock, else timeout after 20 secs - + var counter = new TimeoutCounter(); counter.kill_process_on_timeout("cryptsetup", 20, true); string cmd = "cryptsetup luksOpen '%s' '%s'".printf(luks_device.device, luks_name); @@ -1416,7 +1416,7 @@ public class Device : GLib.Object{ Posix.system(cmd); counter.stop(); log_msg(""); - + } else{ @@ -1426,7 +1426,7 @@ public class Device : GLib.Object{ escape_single_quote(luks_pass), luks_device.device, luks_name); log_debug(cmd.replace(escape_single_quote(luks_pass), "**PASSWORD**")); - + int status = exec_script_sync(cmd, out std_out, out std_err, false, true); switch (status){ @@ -1449,7 +1449,7 @@ public class Device : GLib.Object{ // show input prompt log_debug("Prompting user for passphrase.."); - + luks_pass = gtk_inputbox( _("Encrypted Device"), _("Enter passphrase to unlock '%s'").printf(luks_device.name), @@ -1472,7 +1472,7 @@ public class Device : GLib.Object{ escape_single_quote(luks_pass), luks_device.device, luks_name); log_debug(cmd.replace(escape_single_quote(luks_pass), "**PASSWORD**")); - + int status = exec_script_sync(cmd, out std_out, out std_err, false, true); switch (status){ @@ -1484,7 +1484,7 @@ public class Device : GLib.Object{ break; } } - + } // find unlocked device @@ -1492,7 +1492,7 @@ public class Device : GLib.Object{ foreach(var part in list){ if (part.pkname == luks_device.kname){ unlocked_device = part; - break; + break; } } @@ -1515,7 +1515,7 @@ public class Device : GLib.Object{ } public static bool luks_lock(string kname, Gtk.Window? parent_window){ - + var cmd = "cryptsetup luksClose %s".printf(kname); log_debug(cmd); @@ -1524,18 +1524,18 @@ public class Device : GLib.Object{ int status = exec_script_sync(cmd, out std_out, out std_err, false, true); log_msg(std_out); log_msg(std_err); - + if (status != 0){ if (parent_window != null){ string msg = "Failed to lock device: %s".printf(kname); gtk_messagebox("Error", msg, parent_window, true); } } - + return (status == 0); - + /*log_debug(cmd); - + if (bash_admin_shell != null){ int status = bash_admin_shell.execute(cmd); return (status == 0); @@ -1551,7 +1551,7 @@ public class Device : GLib.Object{ /* * Mounts specified device at specified mount point. - * + * * */ string cmd = ""; @@ -1563,7 +1563,7 @@ public class Device : GLib.Object{ string uuid = ""; // resolve uuid and device name ---------- - + if (dev_name_or_uuid.has_prefix("/dev")){ device = dev_name_or_uuid; uuid = get_device_uuid(dev_name_or_uuid); @@ -1575,7 +1575,7 @@ public class Device : GLib.Object{ } // check if already mounted -------------- - + var mps = Device.get_device_mount_points(dev_name_or_uuid); log_debug("------------------"); @@ -1584,7 +1584,7 @@ public class Device : GLib.Object{ log_debug(mp.mount_point); } log_debug("------------------"); - + foreach(var mp in mps){ if ((mp.mount_point == mount_point) && mp.mount_options.contains(mount_options)){ if (!silent){ @@ -1605,7 +1605,7 @@ public class Device : GLib.Object{ unmount(mount_point); // mount the device ------------------- - + if (mount_options.length > 0){ cmd = "mount -o %s \"%s\" \"%s\"".printf(mount_options, device, mount_point); } @@ -1630,7 +1630,7 @@ public class Device : GLib.Object{ } return true; } - + // check if mounted successfully ------------------ /*mps = Device.get_device_mount_points(dev_name_or_uuid); @@ -1783,7 +1783,7 @@ public class Device : GLib.Object{ if (has_parent() && (parent.type == "part")){ text += " (%s)".printf(pkname); } - + return text; } } @@ -1795,7 +1795,7 @@ public class Device : GLib.Object{ if (has_parent() && (parent.type == "part")){ text += " (%s)".printf(parent.kname); } - + return text; } } @@ -1830,13 +1830,13 @@ public class Device : GLib.Object{ return s.strip(); } - + public string description_simple(){ return description_simple_formatted().replace("","").replace("",""); } - + public string description_simple_formatted(){ - + string s = ""; if (type == "disk"){ @@ -1902,7 +1902,7 @@ public class Device : GLib.Object{ s += (uuid.length > 0) ? " ~ " + uuid : ""; s += (fstype.length > 0) ? " ~ " + fstype : ""; s += (used.length > 0) ? " ~ " + used + " / " + size + " GB used (" + used_percent + ")" : ""; - + return s; } @@ -1941,7 +1941,7 @@ public class Device : GLib.Object{ else{ tt += "%-15s: %s\n".printf(_("Device"), (mapped_name.length > 0) ? "%s → %s".printf(device, mapped_name) : device); - + if (has_parent()){ tt += "%-15s: %s\n".printf(_("Parent Device"), parent.device); } @@ -1949,10 +1949,10 @@ public class Device : GLib.Object{ tt += "%-15s: %s\n".printf(_("Type"),type); tt += "%-15s: %s\n".printf(_("Filesystem"),fstype); tt += "%-15s: %s\n".printf(_("Label"),label); - + tt += "%-15s: %s\n".printf(_("Size"), (size_bytes > 0) ? format_file_size(size_bytes) : "N/A"); - + tt += "%-15s: %s\n".printf(_("Used"), (used_bytes > 0) ? format_file_size(used_bytes) : "N/A"); @@ -1965,13 +1965,13 @@ public class Device : GLib.Object{ // testing ----------------------------------- public static void test_all(){ - + var list = get_block_devices_using_lsblk(); log_msg("\n> get_block_devices_using_lsblk()"); print_device_list(list); log_msg(""); - + //list = get_block_devices_using_blkid(); //log_msg("\nget_block_devices_using_blkid()\n"); //print_device_list(list); @@ -1993,14 +1993,14 @@ public class Device : GLib.Object{ print_device_list(list); print_device_mounts(list); print_device_disk_space(list); - + log_msg(""); } public static void print_device_list(Gee.ArrayList list){ log_debug(""); - + log_debug("%-12s ,%-5s ,%-5s ,%-36s ,%s".printf( "device", "pkname", @@ -2021,7 +2021,7 @@ public class Device : GLib.Object{ } log_debug(""); - + /* log_debug("%-20s %-20s %s %s %s %s".printf( "device", @@ -2046,7 +2046,7 @@ public class Device : GLib.Object{ log_debug(""); */ - + /*log_debug("%-20s %-10s %-15s %-3s %-3s %15s %15s".printf( "device", "type", @@ -2076,7 +2076,7 @@ public class Device : GLib.Object{ public static void print_device_mounts(Gee.ArrayList list){ log_debug(""); - + log_debug("%-15s %s".printf( "device", //"fstype", @@ -2100,7 +2100,7 @@ public class Device : GLib.Object{ //dev.fstype, mps )); - + } log_debug(""); @@ -2108,7 +2108,7 @@ public class Device : GLib.Object{ public static void print_device_disk_space(Gee.ArrayList list){ log_debug(""); - + log_debug("%-15s %-12s %15s %15s %15s %10s".printf( "device", "fstype", diff --git a/src/Utility/FileItem.vala b/src/Utility/FileItem.vala index d20115b..647c5ad 100644 --- a/src/Utility/FileItem.vala +++ b/src/Utility/FileItem.vala @@ -35,7 +35,7 @@ using TeeJee.System; using TeeJee.Misc; public class FileItem : GLib.Object,Gee.Comparable { - + public string file_name = ""; public string file_location = ""; public string file_path = ""; @@ -46,7 +46,7 @@ public class FileItem : GLib.Object,Gee.Comparable { public string owner_user = ""; public string owner_group = ""; public string content_type = ""; - public string file_status = ""; + public string file_status = ""; public bool is_selected = false; public bool is_symlink = false; @@ -59,7 +59,7 @@ public class FileItem : GLib.Object,Gee.Comparable { public GLib.Icon icon; // contructors ------------------------------- - + public FileItem(string name) { file_name = name; } @@ -79,7 +79,7 @@ public class FileItem : GLib.Object,Gee.Comparable { } // properties ------------------------------------------------- - + public int64 size { get{ return _size; @@ -106,11 +106,11 @@ public class FileItem : GLib.Object,Gee.Comparable { //} } } - + // instance methods ------------------------------------------- - + public void query_file_info() { - + try { FileInfo info; File file = File.parse_name (file_path); @@ -118,7 +118,7 @@ public class FileItem : GLib.Object,Gee.Comparable { if (file.query_exists()) { // get type without following symlinks - + info = file.query_info("%s,%s,%s".printf( FileAttribute.STANDARD_TYPE, FileAttribute.STANDARD_ICON, @@ -128,14 +128,14 @@ public class FileItem : GLib.Object,Gee.Comparable { var item_file_type = info.get_file_type(); this.icon = info.get_icon(); - + if (item_file_type == FileType.SYMBOLIC_LINK) { //this.icon = GLib.Icon.new_for_string("emblem-symbolic-link"); this.is_symlink = true; this.symlink_target = info.get_symlink_target(); } else { - + this.is_symlink = false; this.symlink_target = ""; @@ -143,7 +143,7 @@ public class FileItem : GLib.Object,Gee.Comparable { //log_msg(file_basename(file_path) + " (gicon): " + icon.to_string()); /*var themed_icon = (GLib.ThemedIcon) icon; - + string txt = "-> "; foreach(var name in themed_icon.names){ txt += ", " + name; @@ -153,7 +153,7 @@ public class FileItem : GLib.Object,Gee.Comparable { } // get file info - follow symlinks - + info = file.query_info("%s,%s,%s,%s,%s,%s,%s,%s".printf( FileAttribute.STANDARD_TYPE, FileAttribute.STANDARD_SIZE, @@ -175,7 +175,7 @@ public class FileItem : GLib.Object,Gee.Comparable { // content type this.content_type = info.get_content_type(); - + // size if (!this.is_symlink && (this.file_type == FileType.REGULAR)) { this._size = info.get_size(); @@ -189,7 +189,7 @@ public class FileItem : GLib.Object,Gee.Comparable { // owner_group this.owner_group = info.get_attribute_string(FileAttribute.OWNER_GROUP); - + } } catch (Error e) { @@ -198,7 +198,7 @@ public class FileItem : GLib.Object,Gee.Comparable { } public void query_file_info_basic() { - + try { FileInfo info; File file = File.parse_name(file_path); @@ -206,12 +206,12 @@ public class FileItem : GLib.Object,Gee.Comparable { if (file.query_exists()) { // get type and icon -- follow symlinks - + info = file.query_info("%s,%s".printf( FileAttribute.STANDARD_TYPE, FileAttribute.STANDARD_ICON ), 0); - + this.icon = info.get_icon(); this.file_type = info.get_file_type(); diff --git a/src/Utility/FsTabEntry.vala b/src/Utility/FsTabEntry.vala index 855daef..f0045ce 100755 --- a/src/Utility/FsTabEntry.vala +++ b/src/Utility/FsTabEntry.vala @@ -30,10 +30,10 @@ using TeeJee.System; using TeeJee.Misc; public class FsTabEntry : GLib.Object{ - + public bool is_comment = false; public bool is_empty_line = false; - + public string device_string = ""; public string mount_point = ""; public string type = ""; @@ -57,17 +57,17 @@ public class FsTabEntry : GLib.Object{ } public static Gee.ArrayList read_file(string file_path){ - + var list = new Gee.ArrayList(); if (!file_exists(file_path)){ return list; } string text = file_read(file_path); - + string[] lines = text.split("\n"); - + foreach(string line in lines){ - + var entry = new FsTabEntry(); list.add(entry); @@ -75,24 +75,24 @@ public class FsTabEntry : GLib.Object{ entry.is_empty_line = (line.strip().length == 0); if (entry.is_comment){ - + entry.line = line; } else if (entry.is_empty_line){ - + entry.line = ""; } else{ entry.line = line; string[] parts = line.replace("\t"," ").split(" "); - + int part_num = -1; - + foreach(string part in parts){ - + if (part.strip().length == 0) { continue; } - + switch (++part_num){ case 0: entry.device_string = part.strip(); @@ -123,13 +123,13 @@ public class FsTabEntry : GLib.Object{ public static string write_file( Gee.ArrayList entries, string file_path, bool keep_comments_and_empty_lines = false){ - + string text = ""; if (!keep_comments_and_empty_lines){ text += "# \n\n"; } - + foreach(var entry in entries){ if (entry.is_comment || entry.is_empty_line){ if (keep_comments_and_empty_lines){ @@ -149,18 +149,18 @@ public class FsTabEntry : GLib.Object{ entries.sort((a, b)=>{ return strcmp(a.mount_point, b.mount_point); }); - + if (file_exists(file_path)){ file_delete(file_path); } - + file_write(file_path, text); - + return text; } public string subvolume_name(){ - + if (options.down().contains("subvol=")){ string txt = options.split("subvol=")[1].split(",")[0].strip(); if (txt.has_prefix("/") && (txt.split("/").length == 2)){ @@ -183,7 +183,7 @@ public class FsTabEntry : GLib.Object{ || (mount_point == "none") || !mount_point.has_prefix("/") || (!device_string.has_prefix("/dev/") && !device_string.down().has_prefix("uuid="))){ - + return false; } else{ @@ -192,7 +192,7 @@ public class FsTabEntry : GLib.Object{ } public static FsTabEntry? find_entry_by_mount_point(Gee.ArrayList entries, string mount_path){ - + foreach(var entry in entries){ if (entry.mount_point == mount_path){ return entry; @@ -202,7 +202,7 @@ public class FsTabEntry : GLib.Object{ } public Device? resolve_device(Gee.ArrayList crypttab, Gtk.Window? parent_window){ - + Device dev_fstab = null; if (device_uuid.length > 0){ dev_fstab = Device.get_device_by_uuid(device_uuid); @@ -217,30 +217,30 @@ public class FsTabEntry : GLib.Object{ Check if the device mentioned in fstab entry is a mapped device. If it is, then try finding the parent device which may be available on the current system. Prompt user to unlock it if found. - + Note: Mapped name may be different on running system, or it may be same. Since it is not reliable, we will try to identify the parent intead of the mapped device. */ - + if (device_string.has_prefix("/dev/mapper/")){ - + string mapped_name = device_string.replace("/dev/mapper/",""); - + foreach(var item in crypttab){ - + if (item.mapped_name == mapped_name){ // we found the entry for the mapped device device_string = item.device_string; if (device_uuid.length > 0){ - + // we have the parent's uuid. get the luks device and prompt user to unlock it. var dev_luks = Device.get_device_by_uuid(device_uuid); - + if (dev_luks != null){ - + string msg_out, msg_err; var dev_unlocked = Device.luks_unlock( dev_luks, "", "", parent_window, out msg_out, out msg_err); @@ -268,22 +268,22 @@ public class FsTabEntry : GLib.Object{ public void append_option(string option){ - + if (!options.contains(option)){ options += ",%s".printf(option); } - + if(options.has_prefix(",")){ options = options[1:options.length]; } - + options = options.strip(); } public void remove_option(string option){ - + options = options.replace(option,"").strip(); - + if(options.has_prefix(",")){ options = options[1:options.length]; } diff --git a/src/Utility/Gtk/AboutWindow.vala b/src/Utility/Gtk/AboutWindow.vala index c00da29..6d8db8d 100644 --- a/src/Utility/Gtk/AboutWindow.vala +++ b/src/Utility/Gtk/AboutWindow.vala @@ -32,7 +32,7 @@ using TeeJee.System; using TeeJee.Misc; public class AboutWindow : Gtk.Window { - + private Gtk.Box vbox_main; private Gtk.Box vbox_logo; private Gtk.Box vbox_credits; @@ -81,7 +81,7 @@ public class AboutWindow : Gtk.Window { _contributors = value; } } - + private string _comments = ""; public string comments{ get{ @@ -161,7 +161,7 @@ public class AboutWindow : Gtk.Window { _translators = value; } } - + private string[] _third_party; public string[] third_party{ get{ @@ -203,11 +203,11 @@ public class AboutWindow : Gtk.Window { } private string username = ""; - + public AboutWindow(Gtk.Window _window) { window = _window; - + window_position = WindowPosition.CENTER_ON_PARENT; set_destroy_with_parent (true); set_modal (true); @@ -218,17 +218,17 @@ public class AboutWindow : Gtk.Window { username = get_username(); log_debug("username: %s".printf(username)); } - + vbox_main = new Gtk.Box(Orientation.VERTICAL,0); vbox_main.margin = 12; vbox_main.spacing = 6; this.add(vbox_main); - + vbox_logo = new Gtk.Box(Orientation.VERTICAL,0); vbox_main.add(vbox_logo); // license ------------------------------------- - + vbox_license = new Gtk.Box(Orientation.VERTICAL,0); vbox_license.no_show_all = true; vbox_main.add(vbox_license); @@ -237,7 +237,7 @@ public class AboutWindow : Gtk.Window { sw_license.set_shadow_type(ShadowType.ETCHED_IN); sw_license.expand = true; vbox_license.add(sw_license); - + var label = new Gtk.Label(""); label.set_use_markup(true); label.margin_top = 5; @@ -250,9 +250,9 @@ public class AboutWindow : Gtk.Window { label.margin = 6; sw_license.add(label); lbl_license = label; - + // credits -------------------------------- - + vbox_credits = new Gtk.Box(Orientation.VERTICAL,0); vbox_credits.no_show_all = true; vbox_main.add(vbox_credits); @@ -261,11 +261,11 @@ public class AboutWindow : Gtk.Window { sw_credits.set_shadow_type(ShadowType.ETCHED_IN); sw_credits.expand = true; vbox_credits.add(sw_credits); - + vbox_lines = new Gtk.Box(Orientation.VERTICAL,0); vbox_lines.margin_top = 10; sw_credits.add(vbox_lines); - + //logo img_logo = new Gtk.Image(); img_logo.margin_top = 6; @@ -295,7 +295,7 @@ public class AboutWindow : Gtk.Window { vbox_logo.add(lbtn_website); lbtn_website.activate_link.connect(()=>{ - return xdg_open(lbtn_website.uri, username); + return xdg_open(lbtn_website.uri, username); }); //copyright @@ -332,13 +332,13 @@ public class AboutWindow : Gtk.Window { hbox_action.add(btn_close); // handlers - + btn_license.clicked.connect(()=>{ - + vbox_logo.visible = !vbox_logo.visible; vbox_license.visible = !vbox_license.visible; - + if (vbox_license.visible){ vbox_license.set_no_show_all(false); vbox_license.show_all(); @@ -366,7 +366,7 @@ public class AboutWindow : Gtk.Window { }); btn_credits.clicked.connect(()=>{ - + vbox_logo.visible = !vbox_logo.visible; vbox_credits.visible = !vbox_credits.visible; @@ -400,7 +400,7 @@ public class AboutWindow : Gtk.Window { } public void initialize() { - + title = program_name; img_logo.pixbuf = logo.scale_simple(128,128,Gdk.InterpType.HYPER); lbl_program_name.label = "%s".printf(program_name); @@ -479,7 +479,7 @@ public class AboutWindow : Gtk.Window { } private void add_line(string text, bool escape_html_chars = true){ - + if (text.split(":").length >= 2){ var link = new LinkButton(escape_html(text.split(":")[0])); vbox_lines.add(link); @@ -496,7 +496,7 @@ public class AboutWindow : Gtk.Window { } link.activate_link.connect(()=>{ - return xdg_open(link.uri, username); + return xdg_open(link.uri, username); }); } else{ diff --git a/src/Utility/Gtk/CustomMessageDialog.vala b/src/Utility/Gtk/CustomMessageDialog.vala index a60db71..e02c815 100644 --- a/src/Utility/Gtk/CustomMessageDialog.vala +++ b/src/Utility/Gtk/CustomMessageDialog.vala @@ -34,7 +34,7 @@ using TeeJee.System; using TeeJee.Misc; public class CustomMessageDialog : Gtk.Dialog { - + private Gtk.Box vbox_main; private Gtk.Label lbl_msg; private Gtk.ScrolledWindow sw_msg; @@ -47,9 +47,9 @@ public class CustomMessageDialog : Gtk.Dialog { private string msg_body; private Gtk.MessageType msg_type; private Gtk.ButtonsType buttons_type; - + public CustomMessageDialog(string _msg_title, string _msg_body, Gtk.MessageType _msg_type, Window? parent, Gtk.ButtonsType _buttons_type) { - + set_transient_for(parent); set_modal(true); @@ -57,7 +57,7 @@ public class CustomMessageDialog : Gtk.Dialog { msg_body = _msg_body; msg_type = _msg_type; buttons_type = _buttons_type; - + init_window(); lbl_msg.expand = true; @@ -75,7 +75,7 @@ public class CustomMessageDialog : Gtk.Dialog { } public void init_window () { - + this.title = ""; this.window_position = WindowPosition.CENTER_ON_PARENT; this.icon = IconManager.lookup("timeshift", 16); @@ -83,7 +83,7 @@ public class CustomMessageDialog : Gtk.Dialog { this.deletable = false; this.skip_taskbar_hint = true; this.skip_pager_hint = true; - + //vbox_main vbox_main = get_content_area () as Gtk.Box; vbox_main.margin = 6; @@ -94,7 +94,7 @@ public class CustomMessageDialog : Gtk.Dialog { vbox_main.add (hbox_contents); string icon_name = "dialog-info"; - + switch(msg_type){ case Gtk.MessageType.INFO: icon_name = "dialog-info"; @@ -111,10 +111,10 @@ public class CustomMessageDialog : Gtk.Dialog { } // image ---------------- - + var img = new Image.from_icon_name(icon_name, Gtk.IconSize.DIALOG); hbox_contents.add(img); - + // label ------------------- var text = "%s\n\n%s".printf( @@ -138,7 +138,7 @@ public class CustomMessageDialog : Gtk.Dialog { hbox_contents.add(sw_msg); // actions ------------------------- - + switch(buttons_type){ case Gtk.ButtonsType.OK: btn_ok = (Gtk.Button) add_button (_("OK"), Gtk.ResponseType.OK); @@ -154,7 +154,7 @@ public class CustomMessageDialog : Gtk.Dialog { btn_no = (Gtk.Button) add_button (_("No"), Gtk.ResponseType.NO); btn_yes.grab_focus(); break; - + } } } diff --git a/src/Utility/Gtk/DonationWindow.vala b/src/Utility/Gtk/DonationWindow.vala index 87e0da1..9fc7ceb 100755 --- a/src/Utility/Gtk/DonationWindow.vala +++ b/src/Utility/Gtk/DonationWindow.vala @@ -41,10 +41,10 @@ public class DonationWindow : Gtk.Window { public DonationWindow(Gtk.Window window) { set_title(_("Donate")); - + set_transient_for(window); set_destroy_with_parent(true); - + window_position = WindowPosition.CENTER_ON_PARENT; set_modal(true); @@ -56,7 +56,7 @@ public class DonationWindow : Gtk.Window { vbox_main.margin = 12; this.add(vbox_main); - + if (get_user_id_effective() == 0){ username = get_username(); } @@ -70,16 +70,16 @@ public class DonationWindow : Gtk.Window { msg = _("This software is updated once a year due to lack of time, developers, and funds. You can support this project by making a donation with PayPal."); add_label(msg); - + var hbox = add_hbox(); - + add_button(hbox, _("Donate"), "https://www.paypal.com/cgi-bin/webscr?business=teejeetech@gmail.com&cmd=_xclick¤cy_code=USD&item_name=%s+Donation".printf(appname)); // ----------------------------- - + msg = _("Use the GitHub issue tracker for reporting issues, or post your questions on the Linux Mint forums. Please avoid reporting issues by email."); - + add_label(msg); hbox = add_vbox(); @@ -89,21 +89,21 @@ public class DonationWindow : Gtk.Window { if (has_wiki){ add_button(hbox, _("Wiki"), "https://github.com/teejee2008/%s/wiki".printf(appname.down())); } - + // close window --------------------------------------------------------- var lbl_dummy = add_label(""); lbl_dummy.margin = 20; - + hbox = add_hbox(); add_button(hbox, _("Visit Website"), "https://teejeetech.com/"); add_button(hbox, _("More Apps"), "https://teejeetech.com/shop/"); - + var button = new Gtk.Button.with_label(_("Close")); hbox.add(button); - + button.clicked.connect(() => { this.destroy(); }); @@ -112,20 +112,20 @@ public class DonationWindow : Gtk.Window { } private void add_heading(string msg){ - + var label = new Gtk.Label("%s".printf(msg)); label.set_use_markup(true); - + label.wrap = true; label.wrap_mode = Pango.WrapMode.WORD; label.max_width_chars = 80; - + label.xalign = 0.0f; label.margin_top = 12; vbox_main.add(label); } - + private string format_heading(string msg){ return "%s".printf(msg); @@ -134,17 +134,17 @@ public class DonationWindow : Gtk.Window { private Gtk.Label add_label(string msg){ var label = new Gtk.Label(msg); - + label.set_use_markup(true); - + label.wrap = true; label.wrap_mode = Pango.WrapMode.WORD; label.max_width_chars = 50; - + label.xalign = 0.0f; vbox_main.add(label); - + return label; } @@ -156,7 +156,7 @@ public class DonationWindow : Gtk.Window { vbox_main.add(hbox); return hbox; } - + private Gtk.ButtonBox add_vbox(){ var vbox = new Gtk.ButtonBox(Orientation.VERTICAL); @@ -173,7 +173,7 @@ public class DonationWindow : Gtk.Window { box.add(button); //button.set_size_request(200,-1); - + button.clicked.connect(() => { xdg_open(url, username); }); @@ -184,7 +184,7 @@ public class DonationWindow : Gtk.Window { var button = new Gtk.LinkButton.with_label("", text); button.set_tooltip_text(url); box.add(button); - + button.clicked.connect(() => { xdg_open(url, username); }); diff --git a/src/Utility/Gtk/TerminalWindow.vala b/src/Utility/Gtk/TerminalWindow.vala index b84848d..14eeb5f 100644 --- a/src/Utility/Gtk/TerminalWindow.vala +++ b/src/Utility/Gtk/TerminalWindow.vala @@ -34,52 +34,52 @@ using TeeJee.System; using TeeJee.Misc; public class TerminalWindow : Gtk.Window { - + private Gtk.Box vbox_main; private Vte.Terminal term; - + private int def_width = 800; private int def_height = 600; private Pid child_pid; private Gtk.Window parent_win = null; public bool is_running = false; - + // init - + public TerminalWindow.with_parent(Gtk.Window? parent) { - + if (parent != null){ set_transient_for(parent); parent_win = parent; } - + set_modal(true); fullscreen(); this.delete_event.connect(()=>{ - // do not allow window to close + // do not allow window to close return true; }); - + init_window(); } public void init_window () { - + this.title = ""; this.icon = IconManager.lookup("timeshift",16); this.resizable = true; this.deletable = false; - + // vbox_main --------------- - + vbox_main = new Gtk.Box(Orientation.VERTICAL, 6); vbox_main.set_size_request (def_width, def_height); add (vbox_main); // terminal ---------------------- - + term = new Vte.Terminal(); term.expand = true; vbox_main.add(term); @@ -89,33 +89,33 @@ public class TerminalWindow : Gtk.Window { term.cursor_blink_mode = Vte.CursorBlinkMode.SYSTEM; term.cursor_shape = Vte.CursorShape.UNDERLINE; term.rewrap_on_resize = true; - + term.scroll_on_keystroke = true; term.scroll_on_output = true; // colors ----------------------------- - + var color = Gdk.RGBA(); color.parse("#FFFFFF"); term.set_color_foreground(color); color.parse("#404040"); term.set_color_background(color); - + // grab focus ---------------- - + term.grab_focus(); - + show_all(); } public void start_shell(){ - + string[] argv = new string[1]; argv[0] = "/bin/sh"; string[] env = Environ.get(); - + try{ is_running = true; @@ -137,16 +137,16 @@ public class TerminalWindow : Gtk.Window { } public void execute_script(string script_path, bool wait = false){ - + string[] argv = new string[1]; argv[0] = script_path; - + string[] env = Environ.get(); try{ is_running = true; - + term.spawn_sync( Vte.PtyFlags.DEFAULT, //pty_flags TEMP_DIR, //working_directory @@ -159,7 +159,7 @@ public class TerminalWindow : Gtk.Window { ); term.watch_child(child_pid); - + term.child_exited.connect(script_exit); if (wait){ @@ -177,11 +177,11 @@ public class TerminalWindow : Gtk.Window { public void script_exit(int status){ is_running = false; - + this.hide(); //no need to check status again - + //destroying parent will display main window if (parent != null){ parent_win.destroy(); diff --git a/src/Utility/GtkHelper.vala b/src/Utility/GtkHelper.vala index a8403be..9ac2f7e 100644 --- a/src/Utility/GtkHelper.vala +++ b/src/Utility/GtkHelper.vala @@ -12,7 +12,7 @@ namespace TeeJee.GtkHelper{ using Gtk; // messages ----------- - + public void show_err_log(Gtk.Window parent, bool disable_log = true){ if ((err_log != null) && (err_log.length > 0)){ gtk_messagebox(_("Error"), err_log, parent, true); @@ -22,7 +22,7 @@ namespace TeeJee.GtkHelper{ err_log_disable(); } } - + public void gtk_do_events (){ /* Do pending events */ @@ -113,11 +113,11 @@ namespace TeeJee.GtkHelper{ vbox_main.pack_start (txt_input, false, true, 0); content.add(vbox_main); content.margin = 6; - + //add buttons dlg.add_button(_("OK"),Gtk.ResponseType.OK); dlg.add_button(_("Cancel"),Gtk.ResponseType.CANCEL); - + //keyboard shortcuts txt_input.key_press_event.connect ((w, event) => { if (event.keyval == 65293) { @@ -150,9 +150,9 @@ namespace TeeJee.GtkHelper{ } window.destroy(); } - + // combo --------- - + public bool gtk_combobox_set_value (ComboBox combo, int index, string val){ /* Conveniance function to set combobox value */ @@ -203,7 +203,7 @@ namespace TeeJee.GtkHelper{ return val; } - + public int gtk_combobox_get_value_enum (ComboBox combo, int index, int default_value){ /* Conveniance function to get combobox value */ @@ -222,7 +222,7 @@ namespace TeeJee.GtkHelper{ // styles ---------------- public static int CSS_AUTO_CLASS_INDEX = 0; - + public static void gtk_apply_css(Gtk.Widget[] widgets, string css_style){ var css_provider = new Gtk.CssProvider(); var css = ".style_%d { %s }".printf(++CSS_AUTO_CLASS_INDEX, css_style); @@ -233,16 +233,16 @@ namespace TeeJee.GtkHelper{ } foreach(var widget in widgets){ - + widget.get_style_context().add_provider( css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - + widget.get_style_context().add_class("style_%d".printf(CSS_AUTO_CLASS_INDEX)); } } - + // treeview ----------------- - + public int gtk_treeview_model_count(TreeModel model){ int count = 0; TreeIter iter; @@ -260,9 +260,9 @@ namespace TeeJee.GtkHelper{ treeview.model = null; treeview.model = model; } - + // misc - + public bool gtk_container_has_child(Gtk.Container container, Gtk.Widget widget){ foreach(var child in container.get_children()){ if (child == widget){ @@ -273,7 +273,7 @@ namespace TeeJee.GtkHelper{ } // file chooser ---------------- - + public Gtk.FileFilter create_file_filter(string group_name, string[] patterns) { var filter = new Gtk.FileFilter (); filter.set_filter_name(group_name); @@ -287,21 +287,21 @@ namespace TeeJee.GtkHelper{ // add_notebook private Gtk.Notebook add_notebook(Gtk.Box box, bool show_tabs = true, bool show_border = true){ - + // notebook var book = new Gtk.Notebook(); book.margin = 0; book.show_tabs = show_tabs; book.show_border = show_border; - + box.pack_start(book, true, true, 0); - + return book; } // add_treeview private Gtk.TreeView add_treeview(Gtk.Box box, Gtk.SelectionMode selection_mode = Gtk.SelectionMode.SINGLE){ - + // TreeView var treeview = new TreeView(); treeview.get_selection().mode = selection_mode; @@ -320,26 +320,26 @@ namespace TeeJee.GtkHelper{ // add_column_text private Gtk.TreeViewColumn add_column_text(Gtk.TreeView treeview, string title, out Gtk.CellRendererText cell){ - + // TreeViewColumn var col = new Gtk.TreeViewColumn(); col.title = title; - + cell = new Gtk.CellRendererText(); cell.xalign = (float) 0.0; col.pack_start (cell, false); treeview.append_column(col); - + return col; } // add_column_icon private Gtk.TreeViewColumn add_column_icon(Gtk.TreeView treeview, string title, out Gtk.CellRendererPixbuf cell){ - + // TreeViewColumn var col = new Gtk.TreeViewColumn(); col.title = title; - + cell = new Gtk.CellRendererPixbuf(); cell.xpad = 2; col.pack_start (cell, false); @@ -351,7 +351,7 @@ namespace TeeJee.GtkHelper{ // add_column_icon_and_text private Gtk.TreeViewColumn add_column_icon_and_text(Gtk.TreeView treeview, string title, out Gtk.CellRendererPixbuf cell_pix, out Gtk.CellRendererText cell_text){ - + // TreeViewColumn var col = new Gtk.TreeViewColumn(); col.title = title; @@ -359,7 +359,7 @@ namespace TeeJee.GtkHelper{ cell_pix = new Gtk.CellRendererPixbuf(); cell_pix.xpad = 2; col.pack_start (cell_pix, false); - + cell_text = new Gtk.CellRendererText(); cell_text.xalign = (float) 0.0; col.pack_start (cell_text, false); @@ -371,7 +371,7 @@ namespace TeeJee.GtkHelper{ // add_column_radio_and_text private Gtk.TreeViewColumn add_column_radio_and_text(Gtk.TreeView treeview, string title, out Gtk.CellRendererToggle cell_radio, out Gtk.CellRendererText cell_text){ - + // TreeViewColumn var col = new Gtk.TreeViewColumn(); col.title = title; @@ -381,7 +381,7 @@ namespace TeeJee.GtkHelper{ cell_radio.radio = true; cell_radio.activatable = true; col.pack_start (cell_radio, false); - + cell_text = new Gtk.CellRendererText(); cell_text.xalign = (float) 0.0; col.pack_start (cell_text, false); @@ -391,9 +391,9 @@ namespace TeeJee.GtkHelper{ } // add_column_icon_radio_text - private Gtk.TreeViewColumn add_column_icon_radio_text(Gtk.TreeView treeview, string title, + private Gtk.TreeViewColumn add_column_icon_radio_text(Gtk.TreeView treeview, string title, out Gtk.CellRendererPixbuf cell_pix, out Gtk.CellRendererToggle cell_radio, out Gtk.CellRendererText cell_text){ - + // TreeViewColumn var col = new Gtk.TreeViewColumn(); col.title = title; @@ -407,7 +407,7 @@ namespace TeeJee.GtkHelper{ cell_radio.radio = true; cell_radio.activatable = true; col.pack_start (cell_radio, false); - + cell_text = new Gtk.CellRendererText(); cell_text.xalign = (float) 0.0; col.pack_start (cell_text, false); @@ -425,7 +425,7 @@ namespace TeeJee.GtkHelper{ scroll.vscrollbar_policy = PolicyType.ALWAYS; scroll.expand = true; box.add(scroll); - + var label = new Gtk.Label(text); label.xalign = (float) 0.0; label.yalign = (float) 0.0; @@ -452,13 +452,13 @@ namespace TeeJee.GtkHelper{ // add_label private Gtk.Label add_label(Gtk.Box box, string text, bool bold = false, bool italic = false, bool large = false){ - + string msg = "%s".printf( (bold ? " weight=\"bold\"" : ""), (italic ? " style=\"italic\"" : ""), (large ? " size=\"x-large\"" : ""), text); - + var label = new Gtk.Label(msg); label.set_use_markup(true); label.xalign = (float) 0.0; @@ -469,19 +469,19 @@ namespace TeeJee.GtkHelper{ } private string format_text(string text, bool bold = false, bool italic = false, bool large = false){ - + string msg = "%s".printf( (bold ? " weight=\"bold\"" : ""), (italic ? " style=\"italic\"" : ""), (large ? " size=\"x-large\"" : ""), escape_html(text)); - + return msg; } // add_label_header private Gtk.Label add_label_header(Gtk.Box box, string text, bool large_heading = false){ - + var label = add_label(box, escape_html(text), true, false, large_heading); label.margin_bottom = 12; return label; @@ -489,7 +489,7 @@ namespace TeeJee.GtkHelper{ // add_label_subnote private Gtk.Label add_label_subnote(Gtk.Box box, string text){ - + var label = add_label(box, text, false, true); return label; } @@ -507,7 +507,7 @@ namespace TeeJee.GtkHelper{ } radio.label = text; - + box.add(radio); foreach(var child in radio.get_children()){ @@ -517,7 +517,7 @@ namespace TeeJee.GtkHelper{ break; } } - + return radio; } @@ -535,7 +535,7 @@ namespace TeeJee.GtkHelper{ break; } } - + /* chk.toggled.connect(()=>{ chk.active; @@ -564,7 +564,7 @@ namespace TeeJee.GtkHelper{ // add_button private Gtk.Button add_button(Gtk.Box box, string text, string tooltip, Gtk.SizeGroup? size_group, Gtk.Image? icon = null){ - + var button = new Gtk.Button(); box.add(button); @@ -582,8 +582,8 @@ namespace TeeJee.GtkHelper{ return button; } - - public Gtk.ButtonBox add_button_box(Gtk.Container box, Gtk.Orientation orientation = Gtk.Orientation.HORIZONTAL, + + public Gtk.ButtonBox add_button_box(Gtk.Container box, Gtk.Orientation orientation = Gtk.Orientation.HORIZONTAL, Gtk.ButtonBoxStyle layout = Gtk.ButtonBoxStyle.CENTER, int spacing = 6){ var bbox = new Gtk.ButtonBox(orientation); @@ -600,7 +600,7 @@ namespace TeeJee.GtkHelper{ SPREAD - Buttons are evenly spread across the box. START - Buttons are grouped towards the start of the box, (on the left for a HBox, or the top for a VBox). */ - + return bbox; } } diff --git a/src/Utility/IconManager.vala b/src/Utility/IconManager.vala index 0155c63..5376456 100644 --- a/src/Utility/IconManager.vala +++ b/src/Utility/IconManager.vala @@ -61,7 +61,7 @@ public class IconManager : GLib.Object { public static void init(string[] args, string app_name){ log_debug("IconManager: init()"); - + search_paths = new Gee.ArrayList(); string binpath = file_resolve_executable_path(args[0]); @@ -91,7 +91,7 @@ public class IconManager : GLib.Object { public static void refresh_icon_theme(){ if (!GTK_INITIALIZED) { return; } - + theme = Gtk.IconTheme.get_default(); foreach(string path in search_paths){ theme.append_search_path(path); @@ -99,7 +99,7 @@ public class IconManager : GLib.Object { } public static Gdk.Pixbuf? lookup(string icon_name, int icon_size, bool symbolic = false, bool use_hardcoded = false, int scale = 1){ - + Gdk.Pixbuf? pixbuf = null; if (icon_name.length == 0){ return null; } @@ -130,7 +130,7 @@ public class IconManager : GLib.Object { return pixbuf; } - + public static Gtk.Image? lookup_image(string icon_name, int icon_size, bool symbolic = false, bool use_hardcoded = false){ if (icon_name.length == 0){ return null; } @@ -138,7 +138,7 @@ public class IconManager : GLib.Object { Gtk.Image image = new Gtk.Image(); Gdk.Pixbuf? pix = lookup(icon_name, icon_size, symbolic, use_hardcoded, image.scale_factor); - + if (pix == null){ pix = lookup(GENERIC_ICON_IMAGE_MISSING, icon_size, symbolic, use_hardcoded, image.scale_factor); } @@ -152,9 +152,9 @@ public class IconManager : GLib.Object { public static Cairo.Surface? lookup_surface(string icon_name, int icon_size, int scale = 1, bool symbolic = false, bool use_hardcoded = false){ if (icon_name.length == 0){ return null; } - + Gdk.Pixbuf? pix = lookup(icon_name, icon_size, symbolic, use_hardcoded, scale); - + if (pix == null){ pix = lookup(GENERIC_ICON_IMAGE_MISSING, icon_size, symbolic, use_hardcoded, scale); } @@ -167,7 +167,7 @@ public class IconManager : GLib.Object { Gdk.Pixbuf? pixbuf = null; if (gicon == null){ return null; } - + try { var icon_info = theme.lookup_by_gicon(gicon, icon_size, Gtk.IconLookupFlags.FORCE_SIZE); if (icon_info != null){ @@ -184,7 +184,7 @@ public class IconManager : GLib.Object { public static Gtk.Image? lookup_animation(string gif_name){ if (gif_name.length == 0){ return null; } - + foreach(string search_path in search_paths){ foreach(string ext in new string[] { ".gif" }){ @@ -242,17 +242,17 @@ public class IconManager : GLib.Object { } var emblemed = pixbuf.copy(); - - emblem.composite(emblemed, - offset_x, offset_y, + + emblem.composite(emblemed, + offset_x, offset_y, emblem_size, emblem_size, - offset_x, offset_y, - 1.0, 1.0, + offset_x, offset_y, + 1.0, 1.0, Gdk.InterpType.BILINEAR, 255); return emblemed; } - + public static Gdk.Pixbuf? add_overlay(Gdk.Pixbuf pixbuf_base, Gdk.Pixbuf pixbuf_overlay) { int offset_x = (pixbuf_base.width - pixbuf_overlay.width) / 2 ; @@ -260,35 +260,35 @@ public class IconManager : GLib.Object { var offset_y = (pixbuf_base.height - pixbuf_overlay.height) / 2 ; var emblemed = pixbuf_base.copy(); - - pixbuf_overlay.composite(emblemed, - offset_x, offset_y, + + pixbuf_overlay.composite(emblemed, + offset_x, offset_y, pixbuf_overlay.width, pixbuf_overlay.height, - offset_x, offset_y, - 1.0, 1.0, + offset_x, offset_y, + 1.0, 1.0, Gdk.InterpType.BILINEAR, 255); return emblemed; } - + public static Gdk.Pixbuf? resize_icon(Gdk.Pixbuf pixbuf_image, int icon_size) { - + //log_debug("resize_icon()"); - + var pixbuf_empty = new Gdk.Pixbuf(Gdk.Colorspace.RGB, true, 8, icon_size, icon_size); pixbuf_empty.fill(0x00000000); //log_debug("pixbuf_empty: %d, %d".printf(pixbuf_empty.width, pixbuf_empty.height)); - + var pixbuf_resized = add_overlay(pixbuf_empty, pixbuf_image); - + //log_debug("pixbuf_resized: %d, %d".printf(pixbuf_resized.width, pixbuf_resized.height)); //copy_pixbuf_options(pixbuf_image, pixbuf_resized); - + return pixbuf_resized; } - + public static Gdk.Pixbuf? add_transparency (Gdk.Pixbuf pixbuf, int opacity = 130) { var trans = pixbuf.copy(); @@ -302,14 +302,14 @@ public class IconManager : GLib.Object { return trans; } - + public static Gdk.Pixbuf? load_pixbuf_from_file(string file_path, int icon_size){ - + Gdk.Pixbuf? pixbuf = null; - + int width, height; Gdk.Pixbuf.get_file_info(file_path, out width, out height); - + if ((width <= icon_size) && (height <= icon_size)){ try{ // load without scaling @@ -336,7 +336,7 @@ public class IconManager : GLib.Object { // ignore } } - + return null; } } diff --git a/src/Utility/LinuxDistro.vala b/src/Utility/LinuxDistro.vala index b1fc88b..8f60659 100644 --- a/src/Utility/LinuxDistro.vala +++ b/src/Utility/LinuxDistro.vala @@ -36,7 +36,7 @@ public class LinuxDistro : GLib.Object{ public string codename = ""; public LinuxDistro(){ - + dist_id = ""; description = ""; release = ""; @@ -44,7 +44,7 @@ public class LinuxDistro : GLib.Object{ } public string full_name(){ - + if (dist_id == ""){ return ""; } @@ -197,9 +197,9 @@ public class LinuxDistro : GLib.Object{ } public string dist_type { - + owned get{ - + if (dist_id in "fedora rhel rocky centos almalinux"){ return "redhat"; } diff --git a/src/Utility/MountEntry.vala b/src/Utility/MountEntry.vala index 9660af9..09aa10e 100644 --- a/src/Utility/MountEntry.vala +++ b/src/Utility/MountEntry.vala @@ -8,28 +8,28 @@ using TeeJee.Misc; using Json; public class MountEntry : GLib.Object{ - + public Device device = null; public string mount_point = ""; public string mount_options = ""; - + public MountEntry(Device? device, string mount_point, string mount_options){ - + this.device = device; this.mount_point = mount_point; this.mount_options = mount_options; } public string subvolume_name(){ - + if (mount_options.contains("subvol=")){ - + string txt = mount_options.split("subvol=")[1].split(",")[0].strip(); - + if (txt.has_prefix("/") && (txt.split("/").length == 2)){ txt = txt.split("/")[1]; } - + return txt; } else{ @@ -38,7 +38,7 @@ public class MountEntry : GLib.Object{ } public string lvm_name(){ - + if ((device != null) && (device.type == "lvm") && (device.mapped_name.length > 0)){ return device.mapped_name.strip(); } @@ -48,13 +48,13 @@ public class MountEntry : GLib.Object{ } public static MountEntry? find_entry_by_mount_point(Gee.ArrayList entries, string mount_path){ - + foreach(var entry in entries){ if (entry.mount_point == mount_path){ return entry; } } - + return null; } } diff --git a/src/Utility/OSDNotify.vala b/src/Utility/OSDNotify.vala index 0bc23e4..8d9a777 100644 --- a/src/Utility/OSDNotify.vala +++ b/src/Utility/OSDNotify.vala @@ -28,15 +28,15 @@ using TeeJee.ProcessHelper; // dep: notify-send public class OSDNotify : GLib.Object { - + private static DateTime dt_last_notification = null; public const int NOTIFICATION_INTERVAL = 3; - + public static int notify_send ( string title, string message, int durationMillis, string urgency = "low", // low, normal, critical string dialog_type = "info" //error, info, warning - ){ + ){ /* Displays notification bubble on the desktop */ @@ -54,26 +54,26 @@ public class OSDNotify : GLib.Object { } long seconds = 9999; - + if (dt_last_notification != null){ - + DateTime dt_end = new DateTime.now_local(); TimeSpan elapsed = dt_end.difference(dt_last_notification); seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND); } if (seconds > NOTIFICATION_INTERVAL){ - + if (cmd_exists("notify-send")){ - + string desktop_entry = "timeshift-gtk"; string hint = "string:desktop-entry:%s".printf(desktop_entry); string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\" -h %s".printf( durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message, hint); - + retVal = exec_sync (s, null, null); - + dt_last_notification = new DateTime.now_local(); } } @@ -82,9 +82,9 @@ public class OSDNotify : GLib.Object { } public static bool is_supported(){ - + string path = get_cmd_path("notify-send"); - + return (path != null) && (path.length > 0); } } diff --git a/src/Utility/RsyncTask.vala b/src/Utility/RsyncTask.vala index 796a541..9225f13 100644 --- a/src/Utility/RsyncTask.vala +++ b/src/Utility/RsyncTask.vala @@ -35,7 +35,7 @@ public class RsyncTask : AsyncTask{ public bool delete_after = false; public bool delete_excluded = false; public bool relative = false; - + public string rsync_log_file = ""; public string exclude_from_file = ""; public string link_from_path = ""; @@ -65,7 +65,7 @@ public class RsyncTask : AsyncTask{ public int64 count_unchanged; public StringBuilder log; - + public RsyncTask(){ init_regular_expressions(); status_lines = new GLib.Queue(); @@ -75,7 +75,7 @@ public class RsyncTask : AsyncTask{ if (regex_list != null){ return; // already initialized } - + regex_list = new Gee.HashMap(); /* @@ -107,7 +107,7 @@ public class RsyncTask : AsyncTask{ a ACL information changed. x extended attribute information changed. */ - + try { //Example: status=-1 regex_list["status"] = new Regex( @@ -118,7 +118,7 @@ public class RsyncTask : AsyncTask{ regex_list["log-created"] = new Regex( """[0-9\/]+ [0-9:.]+ \[[0-9]+\] ([<>ch.*])([.fdLDS])[+]{9} (.*)"""); - + regex_list["deleted"] = new Regex( """\*deleting[ \t]+(.*)"""); @@ -136,7 +136,7 @@ public class RsyncTask : AsyncTask{ regex_list["log-unchanged"] = new Regex( """[0-9\/]+ [0-9:.]+ \[[0-9]+\] ([.h])([.fdLDS])[ ]{9} (.*)"""); - + regex_list["total-size"] = new Regex( """total size is ([0-9,]+)[ \t]+speedup is [0-9.]+"""); @@ -145,12 +145,12 @@ public class RsyncTask : AsyncTask{ log_error (e.message); } } - + public void prepare() { string script_text = build_script(); - + log_debug(script_text); - + save_bash_script_temp(script_text, script_file); log_debug("RsyncTask:prepare(): saved: %s".printf(script_file)); @@ -173,7 +173,7 @@ public class RsyncTask : AsyncTask{ } private string build_script() { - + var cmd = "export LC_ALL=C.UTF-8\n"; if (io_nice){ @@ -222,15 +222,15 @@ public class RsyncTask : AsyncTask{ if (dry_run){ cmd += " --dry-run"; } - + if (link_from_path.length > 0){ if (!link_from_path.has_suffix("/")){ link_from_path = "%s/".printf(link_from_path); } - + cmd += " --link-dest='%s'".printf(escape_single_quote(link_from_path)); } - + if (rsync_log_file.length > 0){ cmd += " --log-file='%s'".printf(escape_single_quote(rsync_log_file)); } @@ -244,27 +244,27 @@ public class RsyncTask : AsyncTask{ } source_path = remove_trailing_slash(source_path); - + dest_path = remove_trailing_slash(dest_path); - + cmd += " '%s/'".printf(escape_single_quote(source_path)); cmd += " '%s/'".printf(escape_single_quote(dest_path)); - + return cmd; } public Gee.ArrayList parse_log(string log_file_path){ var list = new Gee.ArrayList(); - + string log_file = log_file_path; DataOutputStream dos_changes = null; - + if (!log_file.has_suffix("-changes")){ - + string log_file_changes = log_file_path + "-changes"; - + if (file_exists(log_file_changes)){ // use it log_file = log_file_changes; @@ -306,15 +306,15 @@ public class RsyncTask : AsyncTask{ string item_status = ""; string item_basepath = path_combine(file_parent(log_file_path), "localhost"); - + while ((line = dis.read_line(null)) != null) { prg_count++; - + if (line.strip().length == 0) { continue; } item_path = ""; - + MatchInfo match; if (regex_list["created"].match(line, 0, out match) || regex_list["log-created"].match(line, 0, out match)) { @@ -322,9 +322,9 @@ public class RsyncTask : AsyncTask{ if (dos_changes != null){ dos_changes.put_string("%s\n".printf(line)); } - + //log_debug("matched: created:%s".printf(line)); - + item_path = match.fetch(3).split(" -> ")[0].strip(); /*item_type = FileType.REGULAR; if (match.fetch(2) == "d"){ @@ -337,13 +337,13 @@ public class RsyncTask : AsyncTask{ } else if (regex_list["log-deleted"].match(line, 0, out match) || regex_list["deleted"].match(line, 0, out match)) { - + //log_debug("matched: deleted:%s".printf(line)); if (dos_changes != null){ dos_changes.put_string("%s\n".printf(line)); } - + item_path = match.fetch(1).split(" -> ")[0].strip(); //item_type = item_path.has_suffix("/") ? FileType.DIRECTORY : FileType.REGULAR; item_status = "deleted"; @@ -356,16 +356,16 @@ public class RsyncTask : AsyncTask{ if (dos_changes != null){ dos_changes.put_string("%s\n".printf(line)); } - + item_path = match.fetch(12).split(" -> ")[0].strip(); - + /*if (match.fetch(2) == "d"){ item_type = FileType.DIRECTORY; } else if (match.fetch(2) == "L"){ item_is_symlink = true; }*/ - + if (match.fetch(3) == "c"){ item_status = "checksum"; } @@ -391,9 +391,9 @@ public class RsyncTask : AsyncTask{ else{ log_debug("not-matched: %s".printf(line)); } - + if ((item_path.length > 0) && (item_path != "/./") && (item_path != "./")){ - + item_disk_path = path_combine(item_basepath, item_path); var item = new FileItem.from_disk_path_with_basic_info(item_disk_path); @@ -414,16 +414,16 @@ public class RsyncTask : AsyncTask{ } log_debug("RsyncTask: parse_log(): exit"); - + return list; } - + // execution ---------------------------- public void execute() { - + log_debug("RsyncTask:execute()"); - + prepare(); /*log_debug(string.nfill(70,'=')); @@ -431,12 +431,12 @@ public class RsyncTask : AsyncTask{ log_debug(string.nfill(70,'=')); log_debug(file_read(script_file)); log_debug(string.nfill(70,'='));*/ - + begin(); if (status == AppStatus.RUNNING){ - - + + } } @@ -444,15 +444,15 @@ public class RsyncTask : AsyncTask{ if (is_terminated) { return; } - + update_progress_parse_console_output(out_line); } - + public override void parse_stderr_line(string err_line){ if (is_terminated) { return; } - + update_progress_parse_console_output(err_line); } @@ -467,7 +467,7 @@ public class RsyncTask : AsyncTask{ prg_count = status_line_count; progress = (prg_count * 1.0) / prg_count_total; } - + //MatchInfo match; //if (regex_list["status"].match(line, 0, out match)) { // status_line = match.fetch(12); @@ -481,13 +481,13 @@ public class RsyncTask : AsyncTask{ if (regex_list["created"].match(line, 0, out match)) { //log_debug("matched: created:%s".printf(line)); - + count_created++; status_line = match.fetch(3).split(" -> ")[0].strip(); log.append(line + "\n"); } else if (regex_list["deleted"].match(line, 0, out match)) { - + //log_debug("matched: deleted:%s".printf(line)); count_deleted++; @@ -495,7 +495,7 @@ public class RsyncTask : AsyncTask{ log.append(line + "\n"); } else if (regex_list["unchanged"].match(line, 0, out match)) { - + //log_debug("matched: unchanged:%s".printf(line)); count_unchanged++; @@ -508,7 +508,7 @@ public class RsyncTask : AsyncTask{ count_modified++; status_line = match.fetch(12).split(" -> ")[0].strip(); log.append(line + "\n"); - + if (match.fetch(3) == "c"){ count_checksum++; } @@ -542,7 +542,7 @@ public class RsyncTask : AsyncTask{ } protected override void finish_task(){ - + if ((status != AppStatus.CANCELLED) && (status != AppStatus.PASSWORD_REQUIRED)) { status = AppStatus.FINISHED; } diff --git a/src/Utility/SystemUser.vala b/src/Utility/SystemUser.vala index 3d0e53a..4bc106f 100644 --- a/src/Utility/SystemUser.vala +++ b/src/Utility/SystemUser.vala @@ -27,7 +27,7 @@ using TeeJee.FileSystem; using TeeJee.ProcessHelper; public class SystemUser : GLib.Object { - + public string name = ""; public string password = ""; public int uid = -1; @@ -57,7 +57,7 @@ public class SystemUser : GLib.Object { public bool has_encrypted_private_dirs = false; public Gee.ArrayList encrypted_dirs = new Gee.ArrayList(); public Gee.ArrayList encrypted_private_dirs = new Gee.ArrayList(); - + public bool is_selected = false; public static Gee.HashMap all_users; @@ -67,7 +67,7 @@ public class SystemUser : GLib.Object { } public static void query_users(bool no_passwords = true){ - + if (no_passwords){ all_users = read_users_from_file("/etc/passwd","",""); } @@ -94,13 +94,13 @@ public class SystemUser : GLib.Object { } public static Gee.HashMap read_users_from_file( - + string passwd_file, string shadow_file, string password){ - + var list = new Gee.HashMap(); // read 'passwd' file --------------------------------- - + string txt = file_read(passwd_file); if (txt.length == 0){ @@ -122,7 +122,7 @@ public class SystemUser : GLib.Object { } // read 'shadow' file --------------------------------- - + txt = file_read(shadow_file); if (txt.length == 0){ @@ -140,11 +140,11 @@ public class SystemUser : GLib.Object { } private static SystemUser? parse_line_passwd(string line){ - + if ((line == null) || (line.length == 0)){ return null; } - + SystemUser user = null; //teejee:x:504:504:Tony George:/home/teejee:/bin/bash @@ -182,16 +182,16 @@ public class SystemUser : GLib.Object { log_error("'passwd' file contains a record with non-standard fields" + ": %d".printf(fields.length)); return null; } - + return user; } private static SystemUser? parse_line_shadow(string line, Gee.HashMap list){ - + if ((line == null) || (line.length == 0)){ return null; } - + SystemUser user = null; //root:$1$Etg2ExUZ$F9NTP7omafhKIlqaBMqng1:15651:0:99999:7::: @@ -228,9 +228,9 @@ public class SystemUser : GLib.Object { public void check_encrypted_dirs() { // check encrypted home ------------------------------ - + string ecryptfs_mount_file = "/home/.ecryptfs/%s/.ecryptfs/Private.mnt".printf(name); - + if (file_exists(ecryptfs_mount_file)){ string txt = file_read(ecryptfs_mount_file); @@ -240,7 +240,7 @@ public class SystemUser : GLib.Object { string path = line.strip(); if (path.length == 0){ continue; } - + if (path == home_path){ has_encrypted_home = true; } @@ -252,7 +252,7 @@ public class SystemUser : GLib.Object { // check encrypted Private dirs -------------------------- ecryptfs_mount_file = "%s/.ecryptfs/Private.mnt".printf(home_path); - + if (file_exists(ecryptfs_mount_file)){ string txt = file_read(ecryptfs_mount_file); @@ -262,7 +262,7 @@ public class SystemUser : GLib.Object { string path = line.strip(); if (path.length == 0){ continue; } - + if (path != home_path){ has_encrypted_private_dirs = true; encrypted_private_dirs.add(path); @@ -272,7 +272,7 @@ public class SystemUser : GLib.Object { } } } - + public bool is_system{ get { return ((uid != 0) && (uid < 1000)) || (uid == 65534) || (name == "PinguyBuilder"); // 65534 - nobody diff --git a/src/Utility/TeeJee.FileSystem.vala b/src/Utility/TeeJee.FileSystem.vala index 3a3e628..870a1d1 100644 --- a/src/Utility/TeeJee.FileSystem.vala +++ b/src/Utility/TeeJee.FileSystem.vala @@ -21,7 +21,7 @@ * * */ - + namespace TeeJee.FileSystem{ /* Convenience functions for handling files and directories */ @@ -39,9 +39,9 @@ namespace TeeJee.FileSystem{ public const int64 MiB = 1024 * KiB; public const int64 GiB = 1024 * MiB; public const int64 TiB = 1024 * GiB; - + // path helpers ---------------------------- - + public string file_parent(string file_path){ return File.new_for_path(file_path).get_parent().get_path(); } @@ -62,17 +62,17 @@ namespace TeeJee.FileSystem{ return path; } } - + // file helpers ----------------------------- public bool file_or_dir_exists(string item_path){ - + /* check if item exists on disk*/ var item = File.parse_name(item_path); return item.query_exists(); } - + public bool file_exists (string file_path){ /* Check if file exists */ return (FileUtils.test(file_path, GLib.FileTest.EXISTS) @@ -136,12 +136,12 @@ namespace TeeJee.FileSystem{ try{ dir_create(file_parent(file_path)); - + var file = File.new_for_path (file_path); if (file.query_exists ()) { file.delete (); } - + var file_stream = file.create (FileCreateFlags.REPLACE_DESTINATION); var data_stream = new DataOutputStream (file_stream); data_stream.put_string (contents); @@ -193,7 +193,7 @@ namespace TeeJee.FileSystem{ try { var file = File.new_for_path (file_path); - + if (file.query_exists()) { var info = file.query_info("%s".printf(FileAttribute.STANDARD_TYPE), FileQueryInfoFlags.NOFOLLOW_SYMLINKS); // don't follow symlinks @@ -206,31 +206,31 @@ namespace TeeJee.FileSystem{ catch (Error e) { log_error (e.message); } - + return false; } public bool file_gzip (string src_file){ - + string dst_file = src_file + ".gz"; file_delete(dst_file); - + string cmd = "gzip '%s'".printf(escape_single_quote(src_file)); string std_out, std_err; exec_sync(cmd, out std_out, out std_err); - + return file_exists(dst_file); } public bool file_gunzip (string src_file){ - + string dst_file = src_file; file_delete(dst_file); - + string cmd = "gunzip '%s'".printf(escape_single_quote(src_file)); string std_out, std_err; exec_sync(cmd, out std_out, out std_err); - + return file_exists(dst_file); } @@ -252,20 +252,20 @@ namespace TeeJee.FileSystem{ return path_combine(GLib.Environment.get_current_dir(), file_path); } } - + // file info ----------------- public int64 file_get_size(string file_path){ - + try{ - + File file = File.parse_name (file_path); - + if (FileUtils.test(file_path, GLib.FileTest.EXISTS)){ - + if (FileUtils.test(file_path, GLib.FileTest.IS_REGULAR) && !FileUtils.test(file_path, GLib.FileTest.IS_SYMLINK)){ - + return file.query_info("standard::size",0).get_size(); } } @@ -289,10 +289,10 @@ namespace TeeJee.FileSystem{ catch (Error e) { log_error (e.message); } - + return (new DateTime.from_unix_utc(0)); //1970 } - + public string file_get_symlink_target(string file_path){ try{ FileInfo info; @@ -305,28 +305,28 @@ namespace TeeJee.FileSystem{ catch (Error e) { log_error (e.message); } - + return ""; } // directory helpers ---------------------- - + public bool dir_exists (string dir_path){ /* Check if directory exists */ return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR)); } - + public bool dir_create (string dir_path, bool show_message = false){ /* Creates a directory along with parents */ try{ var dir = File.parse_name (dir_path); - + if (dir.query_exists () == false) { - + bool ok = dir.make_directory_with_parents (null); - + if (show_message){ if (ok){ log_msg(_("Created directory") + ": %s".printf(dir_path)); @@ -336,7 +336,7 @@ namespace TeeJee.FileSystem{ } } } - + return true; } catch (Error e) { @@ -347,20 +347,20 @@ namespace TeeJee.FileSystem{ } public bool dir_delete (string dir_path, bool show_message = false){ - + /* Recursively deletes directory along with contents */ - + if (!dir_exists(dir_path)){ return true; } - + string cmd = "rm -rf '%s'".printf(escape_single_quote(dir_path)); - + log_debug(cmd); - + string std_out, std_err; int status = exec_sync(cmd, out std_out, out std_err); - + if (show_message){ if (status == 0){ log_msg(_("Deleted directory") + ": %s".printf(dir_path)); @@ -371,7 +371,7 @@ namespace TeeJee.FileSystem{ log_error(std_err); } } - + return (status == 0); } @@ -399,20 +399,20 @@ namespace TeeJee.FileSystem{ } public bool filesystem_supports_hardlinks(string path, out bool is_readonly){ - + bool supports_hardlinks = false; is_readonly = false; - + var test_file = path_combine(path, random_string() + "~"); - + if (file_write(test_file,"")){ - + var test_file2 = path_combine(path, random_string() + "~"); var cmd = "ln '%s' '%s'".printf( escape_single_quote(test_file), escape_single_quote(test_file2)); - + log_debug(cmd); int status = exec_sync(cmd); @@ -421,18 +421,18 @@ namespace TeeJee.FileSystem{ escape_single_quote(test_file)); log_debug(cmd); - + string std_out, std_err; status = exec_sync(cmd, out std_out, out std_err); log_debug("stdout: %s".printf(std_out)); - + int64 count = 0; if (int64.try_parse(std_out, out count)){ if (count > 1){ supports_hardlinks = true; } } - + file_delete(test_file2); // delete if exists file_delete(test_file); } @@ -444,9 +444,9 @@ namespace TeeJee.FileSystem{ } public Gee.ArrayList dir_list_names(string path){ - + var list = new Gee.ArrayList(); - + try { File f_home = File.new_for_path (path); @@ -469,15 +469,15 @@ namespace TeeJee.FileSystem{ return list; } - + public bool chown(string dir_path, string user, string group = user){ string cmd = "chown %s:%s -R '%s'".printf(user, group, escape_single_quote(dir_path)); int status = exec_sync(cmd, null, null); return (status == 0); } - + // dir info ------------------- - + // dep: find wc TODO: rewrite public long dir_count(string path){ @@ -517,7 +517,7 @@ namespace TeeJee.FileSystem{ public string format_file_size ( uint64 size, bool binary_units = false, string unit = "", bool show_units = true, int decimals = 1){ - + uint64 unit_k = binary_units ? 1024 : 1000; uint64 unit_m = binary_units ? 1024 * unit_k : 1000 * unit_k; uint64 unit_g = binary_units ? 1024 * unit_m : 1000 * unit_m; @@ -526,7 +526,7 @@ namespace TeeJee.FileSystem{ //log_debug("size: %'lld".printf(size)); string txt = ""; - + if ((size > unit_t) && ((unit.length == 0) || (unit == "t"))){ txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_t)); if (show_units){ @@ -564,17 +564,17 @@ namespace TeeJee.FileSystem{ } public string escape_single_quote(string file_path){ - + return file_path.replace("'","'\\''"); } - + // dep: chmod public int chmod (string file, string permission){ string cmd = "chmod %s '%s'".printf(permission, escape_single_quote(file)); return exec_sync (cmd, null, null); } - + public int rsync(string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){ /* Sync files with rsync */ diff --git a/src/Utility/TeeJee.Json.vala b/src/Utility/TeeJee.Json.vala index 57c4dfa..3c65f56 100644 --- a/src/Utility/TeeJee.Json.vala +++ b/src/Utility/TeeJee.Json.vala @@ -21,7 +21,7 @@ * * */ - + using Json; namespace TeeJee.JsonHelper{ @@ -70,7 +70,7 @@ namespace TeeJee.JsonHelper{ return def_value; } } - + public uint64 json_get_uint64(Json.Object jobj, string member, uint64 def_value){ if (jobj.has_member(member)){ return uint64.parse(jobj.get_string_member(member)); @@ -85,7 +85,7 @@ namespace TeeJee.JsonHelper{ Json.Object jobj, string member, Gee.ArrayList def_value){ - + if (jobj.has_member(member)){ var jarray = jobj.get_array_member(member); var list = new Gee.ArrayList(); diff --git a/src/Utility/TeeJee.Logging.vala b/src/Utility/TeeJee.Logging.vala index c277d89..b9bab29 100644 --- a/src/Utility/TeeJee.Logging.vala +++ b/src/Utility/TeeJee.Logging.vala @@ -21,7 +21,7 @@ * * */ - + namespace TeeJee.Logging{ /* Functions for logging messages to console and log files */ @@ -73,7 +73,7 @@ namespace TeeJee.Logging{ public void log_error (string message, bool highlight = false, bool is_warning = false){ - + if (!LOG_ENABLE) { return; } string msg = ""; @@ -98,10 +98,10 @@ namespace TeeJee.Logging{ stdout.printf (msg); stdout.flush(); - + try { string str = "[%s] %s: %s\n".printf(timestamp(), prefix, message); - + if (dos_log != null){ dos_log.put_string (str); } diff --git a/src/Utility/TeeJee.Misc.vala b/src/Utility/TeeJee.Misc.vala index 0085151..0513abb 100644 --- a/src/Utility/TeeJee.Misc.vala +++ b/src/Utility/TeeJee.Misc.vala @@ -21,7 +21,7 @@ * * */ - + namespace TeeJee.Misc { /* Various utility functions */ @@ -38,9 +38,9 @@ namespace TeeJee.Misc { Intl.setlocale(GLib.LocaleCategory.COLLATE, type); Intl.setlocale(GLib.LocaleCategory.TIME, type); } - + // timestamp ---------------- - + public string timestamp (bool show_millis = false){ /* Returns a formatted timestamp string */ @@ -48,7 +48,7 @@ namespace TeeJee.Misc { // NOTE: format() does not support milliseconds DateTime now = new GLib.DateTime.now_local(); - + if (show_millis){ var msec = now.get_microsecond () / 1000; return "%s.%03d".printf(now.format("%H:%M:%S"), msec); @@ -78,11 +78,11 @@ namespace TeeJee.Misc { public string format_date(DateTime date){ return date.format ("%Y-%m-%d %H:%M"); } - + public string format_date_12_hour(DateTime date){ return date.format ("%Y-%m-%d %I:%M %p"); } - + public string format_duration (long millis){ /* Converts time in milliseconds to format '00:00:00.0' */ @@ -108,7 +108,7 @@ namespace TeeJee.Misc { txt += "%.0fs".printf(secs); return txt; } - + public double parse_time (string time){ /* Converts time in format '00:00:00.0' to milliseconds */ @@ -127,7 +127,7 @@ namespace TeeJee.Misc { string[] arr = str.split(search); string new_txt = ""; bool first = true; - + foreach(string part in arr){ if (first){ new_txt += part; @@ -148,20 +148,20 @@ namespace TeeJee.Misc { return new_txt; } - + public string escape_html(string html, bool pango_markup = true){ string txt = html; if (pango_markup){ txt = txt .replace("\\u00", "") - .replace("\\x" , ""); + .replace("\\x" , ""); } else{ txt = txt .replace(" ", " "); //pango markup throws an error with   } - + txt = txt .replace("&" , "&") .replace("\"", """) @@ -197,7 +197,7 @@ namespace TeeJee.Misc { public DateTime datetime_from_string (string date_time_string){ /* Converts date time string to DateTime - * + * * Supported inputs: * 'yyyy-MM-dd' * 'yyyy-MM-dd HH' @@ -257,7 +257,7 @@ namespace TeeJee.Misc { private string pad_numbers_in_string( string input, int max_length = 3, char pad_char = '0'){ - + string sequence = ""; string output = ""; bool seq_started = false; @@ -293,7 +293,7 @@ namespace TeeJee.Misc { output += sequence; sequence = ""; } - + return output; } diff --git a/src/Utility/TeeJee.Process.vala b/src/Utility/TeeJee.Process.vala index 33d7037..eb11f6e 100644 --- a/src/Utility/TeeJee.Process.vala +++ b/src/Utility/TeeJee.Process.vala @@ -21,30 +21,30 @@ * * */ - + namespace TeeJee.ProcessHelper{ - + using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.Misc; public string TEMP_DIR; - + /* Convenience functions for executing commands and managing processes */ // execute process --------------------------------- - + public static void init_tmp(string subdir_name){ string std_out, std_err; TEMP_DIR = Environment.get_tmp_dir() + "/" + random_string(); dir_create(TEMP_DIR); chmod(TEMP_DIR, "0750"); - + exec_script_sync("echo 'ok'",out std_out,out std_err, true); - + if ((std_out == null) || (std_out.strip() != "ok")){ - + TEMP_DIR = Environment.get_home_dir() + "/.temp/" + random_string(); dir_create(TEMP_DIR); chmod(TEMP_DIR, "0750"); @@ -58,7 +58,7 @@ namespace TeeJee.ProcessHelper{ dir_create(temp); return temp; } - + public int exec_sync (string cmd, out string? std_out = null, out string? std_err = null){ /* Executes single command synchronously. @@ -75,10 +75,10 @@ namespace TeeJee.ProcessHelper{ return -1; } } - + public int exec_script_sync (string script, out string? std_out = null, out string? std_err = null, - bool supress_errors = false, bool run_as_admin = false, + bool supress_errors = false, bool run_as_admin = false, bool cleanup_tmp = true, bool print_to_terminal = false){ /* Executes commands synchronously. @@ -89,18 +89,18 @@ namespace TeeJee.ProcessHelper{ string sh_file = save_bash_script_temp(script, null, true, supress_errors); string sh_file_admin = ""; - + if (run_as_admin){ - + var script_admin = "#!/bin/bash\n"; script_admin += "pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY"; script_admin += " '%s'".printf(escape_single_quote(sh_file)); - + sh_file_admin = GLib.Path.build_filename(file_parent(sh_file),"script-admin.sh"); save_bash_script_temp(script_admin, sh_file_admin, true, supress_errors); } - + try { string[] argv = new string[1]; if (run_as_admin){ @@ -115,7 +115,7 @@ namespace TeeJee.ProcessHelper{ int exit_code; if (print_to_terminal){ - + Process.spawn_sync ( TEMP_DIR, //working dir argv, //argv @@ -128,7 +128,7 @@ namespace TeeJee.ProcessHelper{ ); } else{ - + Process.spawn_sync ( TEMP_DIR, //working dir argv, //argv @@ -147,7 +147,7 @@ namespace TeeJee.ProcessHelper{ file_delete(sh_file_admin); } } - + return exit_code; } catch (Error e){ @@ -174,7 +174,7 @@ namespace TeeJee.ProcessHelper{ argv[0] = scriptfile; string[] env = Environ.get(); - + Pid child_pid; Process.spawn_async_with_pipes( TEMP_DIR, //working dir @@ -196,7 +196,7 @@ namespace TeeJee.ProcessHelper{ bool force_locale = true, bool supress_errors = false){ string sh_path = script_path; - + /* Creates a temporary bash script with given commands * Returns the script file path */ @@ -251,9 +251,9 @@ namespace TeeJee.ProcessHelper{ public void exec_process_new_session(string command){ exec_script_async("setsid %s &".printf(command)); } - + // find process ------------------------------- - + // dep: which public string get_cmd_path (string cmd_tool){ @@ -288,7 +288,7 @@ namespace TeeJee.ProcessHelper{ string std_out, std_err; exec_sync("pidof \"%s\"".printf(name), out std_out, out std_err); - + if (std_out != null){ string[] arr = std_out.split ("\n"); if (arr.length > 0){ @@ -304,7 +304,7 @@ namespace TeeJee.ProcessHelper{ /* Searches for process using the command line used to start the process. * Returns the process id if found. * */ - + try { FileEnumerator enumerator; FileInfo info; @@ -386,7 +386,7 @@ namespace TeeJee.ProcessHelper{ return (ret_val == 0); } - + // dep: ps TODO: Rewrite using /proc public int[] get_process_children (Pid parent_pid){ @@ -414,7 +414,7 @@ namespace TeeJee.ProcessHelper{ } // manage process --------------------------------- - + public void process_quit(Pid process_pid, bool killChildren = true){ /* Kills specified process and its children (optional). @@ -432,14 +432,14 @@ namespace TeeJee.ProcessHelper{ } } } - + public void process_kill(Pid process_pid, bool killChildren = true){ /* Kills specified process and its children (optional). * Sends signal SIGKILL to the process to kill it forcefully. * It is recommended to use the function process_quit() instead. * */ - + int[] child_pids = get_process_children (process_pid); Posix.kill (process_pid, Posix.Signal.KILL); @@ -472,7 +472,7 @@ namespace TeeJee.ProcessHelper{ public void process_quit_by_name(string cmd_name, string cmd_to_match, bool exact_match){ /* Kills a specific command */ - + string std_out, std_err; exec_sync ("ps w -C '%s'".printf(cmd_name), out std_out, out std_err); //use 'ps ew -C conky' for all users @@ -489,7 +489,7 @@ namespace TeeJee.ProcessHelper{ } // process priority --------------------------------------- - + public void process_set_priority (Pid procID, int prio){ /* Set process priority */ diff --git a/src/Utility/TeeJee.System.vala b/src/Utility/TeeJee.System.vala index 1ecb329..de10066 100644 --- a/src/Utility/TeeJee.System.vala +++ b/src/Utility/TeeJee.System.vala @@ -21,25 +21,25 @@ * * */ - + namespace TeeJee.System{ using TeeJee.ProcessHelper; using TeeJee.Logging; using TeeJee.Misc; using TeeJee.FileSystem; - + // user --------------------------------------------------- public bool user_is_admin(){ - + return (get_user_id_effective() == 0); } - + public int get_user_id(){ // returns actual user id of current user (even for applications executed with sudo and pkexec) - + string pkexec_uid = GLib.Environment.get_variable("PKEXEC_UID"); if (pkexec_uid != null){ @@ -56,7 +56,7 @@ namespace TeeJee.System{ } public int get_user_id_effective(){ - + // returns effective user id (0 for applications executed with sudo and pkexec) int uid = -1; @@ -69,37 +69,37 @@ namespace TeeJee.System{ return uid; } - + public string get_username(){ // returns actual username of current user (even for applications executed with sudo and pkexec) - + return get_username_from_uid(get_user_id()); } public string get_username_effective(){ // returns effective user id ('root' for applications executed with sudo and pkexec) - + return get_username_from_uid(get_user_id_effective()); } public int get_user_id_from_username(string username){ - + // check local user accounts in /etc/passwd ------------------- foreach(var line in file_read("/etc/passwd").split("\n")){ - + var arr = line.split(":"); - + if ((arr.length >= 3) && (arr[0] == username)){ - + return int.parse(arr[2]); } } // not found -------------------- - + log_error("UserId not found for userName: %s".printf(username)); return -1; @@ -108,19 +108,19 @@ namespace TeeJee.System{ public string get_username_from_uid(int user_id){ // check local user accounts in /etc/passwd ------------------- - + foreach(var line in file_read("/etc/passwd").split("\n")){ - + var arr = line.split(":"); - + if ((arr.length >= 3) && (arr[2] == user_id.to_string())){ - + return arr[0]; } } // not found -------------------- - + log_error("Username not found for uid: %d".printf(user_id)); return ""; @@ -129,11 +129,11 @@ namespace TeeJee.System{ public string get_user_home(string username = get_username()){ // check local user accounts in /etc/passwd ------------------- - + foreach(var line in file_read("/etc/passwd").split("\n")){ - + var arr = line.split(":"); - + if ((arr.length >= 6) && (arr[0] == username)){ return arr[5]; @@ -152,7 +152,7 @@ namespace TeeJee.System{ } // application ----------------------------------------------- - + public string get_app_path(){ /* Get path of current process */ @@ -250,7 +250,7 @@ namespace TeeJee.System{ public Gee.ArrayList list_dir_names(string path){ var list = new Gee.ArrayList(); - + try { File f_home = File.new_for_path (path); @@ -276,7 +276,7 @@ namespace TeeJee.System{ } // internet helpers ---------------------- - + public bool shutdown (){ /* Shutdown the system immediately */ @@ -297,7 +297,7 @@ namespace TeeJee.System{ string path = get_cmd_path(command); return ((path != null) && (path.length > 0)); } - + // open ----------------------------- public bool xdg_open (string file, string user = ""){ @@ -327,7 +327,7 @@ namespace TeeJee.System{ string path; int status; - + if (xdg_open_try_first){ //try using xdg-open path = get_cmd_path ("xdg-open"); @@ -340,7 +340,7 @@ namespace TeeJee.System{ foreach(string app_name in new string[]{ "nemo", "nautilus", "thunar", "io.elementary.files", "pantheon-files", "marlin", "dolphin" }){ - + path = get_cmd_path (app_name); if ((path != null)&&(path != "")){ string cmd = "%s '%s'".printf(app_name, escape_single_quote(dir_path)); @@ -369,7 +369,7 @@ namespace TeeJee.System{ string path; int status; string cmd; - + path = get_cmd_path ("exo-open"); if ((path != null)&&(path != "")){ cmd = "exo-open '%s'".printf(escape_single_quote(txt_file)); @@ -394,7 +394,7 @@ namespace TeeJee.System{ string path; int status; //string cmd; - + path = get_cmd_path ("exo-open"); if ((path != null)&&(path != "")){ status = exec_script_async ("exo-open \"" + url + "\""); @@ -417,15 +417,15 @@ namespace TeeJee.System{ } public bool using_efi_boot(){ - + /* Returns true if the system was booted in EFI mode * and false for BIOS mode */ - + return dir_exists("/sys/firmware/efi"); } // timers -------------------------------------------------- - + public GLib.Timer timer_start(){ var timer = new GLib.Timer(); timer.start(); @@ -464,7 +464,7 @@ namespace TeeJee.System{ timer.stop(); } log_msg("%s %lu\n".printf(seconds.to_string(), microseconds)); - } + } public void set_numeric_locale(string type){ Intl.setlocale(GLib.LocaleCategory.NUMERIC, type); diff --git a/src/Utility/TimeoutCounter.vala b/src/Utility/TimeoutCounter.vala index 26b3c7b..5d45534 100644 --- a/src/Utility/TimeoutCounter.vala +++ b/src/Utility/TimeoutCounter.vala @@ -34,14 +34,14 @@ public class TimeoutCounter : GLib.Object { public const int DEFAULT_SECONDS_TO_WAIT = 60; public int seconds_to_wait = 60; public bool exit_app = false; - + public void kill_process_on_timeout( string process_to_kill, int seconds_to_wait = DEFAULT_SECONDS_TO_WAIT, bool exit_app = false){ this.process_to_kill = process_to_kill; this.seconds_to_wait = seconds_to_wait; this.exit_app = exit_app; - + try { active = true; Thread.create (start_counter_thread, true); @@ -55,7 +55,7 @@ public class TimeoutCounter : GLib.Object { this.process_to_kill = ""; this.seconds_to_wait = seconds_to_wait; this.exit_app = true; - + try { active = true; Thread.create (start_counter_thread, true); @@ -68,10 +68,10 @@ public class TimeoutCounter : GLib.Object { public void stop(){ active = false; } - + public void start_counter_thread(){ int secs = 0; - + while (active && (secs < seconds_to_wait)){ Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 1000); secs += 1; diff --git a/src/makefile b/src/makefile index 5ae90ac..d2a8383 100644 --- a/src/makefile +++ b/src/makefile @@ -78,7 +78,7 @@ clean: rm -rfv ../release/*.{run,deb} rm -rfv *.c *.o *.mo rm -fv ${app_name} ${app_name}-gtk - + install: mkdir -p "$(DESTDIR)$(bindir)" mkdir -p "$(DESTDIR)$(sharedir)" @@ -90,7 +90,7 @@ install: mkdir -p "$(DESTDIR)$(appconfdir)" mkdir -p "$(DESTDIR)$(sharedir)/${app_name}" mkdir -p "$(DESTDIR)$(sharedir)/icons" - mkdir -p "$(DESTDIR)$(sharedir)/appdata" + mkdir -p "$(DESTDIR)$(sharedir)/appdata" mkdir -p "$(DESTDIR)$(sharedir)/metainfo" # binary @@ -98,7 +98,7 @@ install: install -m 0755 ${app_name}-gtk "$(DESTDIR)$(bindir)" #install -m 0755 ${app_name}-uninstall "$(DESTDIR)$(bindir)" install -m 0755 ${app_name}-launcher "$(DESTDIR)$(bindir)" - + # shared files cp -dpr --no-preserve=ownership -t "$(DESTDIR)$(sharedir)/${app_name}" ./share/${app_name}/* find $(DESTDIR)$(sharedir)/${app_name} -type d -exec chmod 755 {} \+ @@ -121,7 +121,7 @@ install: chmod --recursive 0644 $(DESTDIR)$(sharedir)/icons/hicolor/*/apps/${app_name}.png # appdata - #install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/appdata" + #install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/appdata" install -m 0644 ../debian/${app_name}.appdata.xml "$(DESTDIR)$(sharedir)/metainfo" # translations @@ -149,7 +149,7 @@ uninstall: # man page rm -f "$(DESTDIR)$(man1dir)/${app_name}.1.gz" - + # app icon rm -f $(DESTDIR)$(sharedir)/icons/hicolor/*/apps/${app_name}.png @@ -157,5 +157,5 @@ uninstall: rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/${app_name}.mo # appdata - rm -f "$(DESTDIR)$(sharedir)/appdata/${app_name}.appdata.xml" + rm -f "$(DESTDIR)$(sharedir)/appdata/${app_name}.appdata.xml" rm -f "$(DESTDIR)$(sharedir)/metainfo/${app_name}.appdata.xml" diff --git a/src/timeshift-uninstall b/src/timeshift-uninstall index 2a8979c..5c86058 100755 --- a/src/timeshift-uninstall +++ b/src/timeshift-uninstall @@ -22,7 +22,7 @@ MSG_INFO() { if [ "$2" == 0 ]; then add_newline='-n' fi - + if [ $COLORS_SUPPORTED -eq 0 ]; then echo -e ${add_newline} "[${Yellow}*${Reset}] ${Green}$1${Reset}" else