From 933284d91a72ff2abbabc1cf4195b951acc42917 Mon Sep 17 00:00:00 2001 From: Yannis Gerlach <100762533+ygerlach@users.noreply.github.com> Date: Tue, 23 Dec 2025 00:24:47 +0100 Subject: [PATCH 1/2] pause snapshots config --- src/Core/Main.vala | 53 +++++++++++++++++++++++++++++++++- src/Utility/TeeJee.System.vala | 14 +++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/Core/Main.vala b/src/Core/Main.vala index 713ff4fd..18630c80 100644 --- a/src/Core/Main.vala +++ b/src/Core/Main.vala @@ -95,6 +95,11 @@ public class Main : GLib.Object{ public int count_hourly = 6; public int count_boot = 5; + // pause snapshots - use snapshots_paused to query this + private string pause_snapshots_this_boot = ""; // if the string contains the current /proc/sys/kernel/random/boot_id: enabled; else: disabled + private long pause_snapshots_until = 0; // unix time until snapshots are allowed again + + // empty in "gui mode" contains mode in "cli mode" public string app_mode = ""; public bool dry_run = false; @@ -1083,7 +1088,13 @@ public class Main : GLib.Object{ public bool create_snapshot (bool is_ondemand, Gtk.Window? parent_win){ log_debug("Main: create_snapshot()"); - + + // in scripted mode and snapshots paused + if(App.cmd_scripted && this.snapshots_paused) { + log_msg("Main: snapshots are currently paused"); + return false; + } + bool status = true; bool update_symlinks = false; @@ -3400,6 +3411,12 @@ public class Main : GLib.Object{ } config.set_array_member("exclude-apps",arr); + if(this.pause_snapshots_until > 0) { + config.set_string_member("pause_snapshots", this.pause_snapshots_until.to_string()); + } else if(this.pause_snapshots_this_boot.length > 0) { + config.set_string_member("pause_snapshots", this.pause_snapshots_this_boot); + } + var json = new Json.Generator(); json.pretty = true; json.indent = 2; @@ -3531,11 +3548,45 @@ public class Main : GLib.Object{ } } + string pause_snapshots = config.get_string_member_with_default("pause_snapshots", ""); + long pause_snapshots_long = 0; + if(long.try_parse(pause_snapshots, out pause_snapshots_long)) { + this.pause_snapshots_until = pause_snapshots_long; + this.pause_snapshots_this_boot = ""; + } else { + this.pause_snapshots_until = 0; + + // read current boot_id + if(TeeJee.System.get_current_boot_id() == pause_snapshots) { + this.pause_snapshots_this_boot = pause_snapshots; + } else { + this.pause_snapshots_this_boot = ""; + } + } + if ((app_mode == "")||(LOG_DEBUG)){ log_msg(_("App config loaded") + ": %s".printf(this.app_conf_path)); } } + /** + Are snapshots currently paused? + */ + public bool snapshots_paused { + get { + // paused until given time + bool isTimePaused = this.pause_snapshots_until > (GLib.get_real_time() / 1000000); + if(!isTimePaused) { + this.pause_snapshots_until = 0; + } + + // paused until reboot + bool bootPaused = this.pause_snapshots_this_boot.length > 0; + + return isTimePaused || bootPaused; + } + } + public void set_first_run_flag(){ first_run = true; diff --git a/src/Utility/TeeJee.System.vala b/src/Utility/TeeJee.System.vala index c3a68144..e1f30fde 100644 --- a/src/Utility/TeeJee.System.vala +++ b/src/Utility/TeeJee.System.vala @@ -151,6 +151,20 @@ namespace TeeJee.System{ return dir_exists("/sys/firmware/efi"); } + private static string? current_boot_id = null; + public static string? get_current_boot_id() { + if(current_boot_id != null) { + return current_boot_id; + } + + current_boot_id = file_read("/proc/sys/kernel/random/boot_id"); + if(null != current_boot_id) { + current_boot_id._strip(); + } + + return current_boot_id; + } + // timers -------------------------------------------------- public GLib.Timer timer_start(){ From bcc98855c285254e3a5d395c2f77486d5b631384 Mon Sep 17 00:00:00 2001 From: Yannis Gerlach <100762533+ygerlach@users.noreply.github.com> Date: Sun, 11 Jan 2026 15:17:11 +0100 Subject: [PATCH 2/2] ui for pausing and unpausing snapshots --- src/Core/Main.vala | 20 +++++++++++- src/Gtk/MainWindow.vala | 67 +++++++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 23 deletions(-) diff --git a/src/Core/Main.vala b/src/Core/Main.vala index 18630c80..d246e03f 100644 --- a/src/Core/Main.vala +++ b/src/Core/Main.vala @@ -97,7 +97,7 @@ public class Main : GLib.Object{ // pause snapshots - use snapshots_paused to query this private string pause_snapshots_this_boot = ""; // if the string contains the current /proc/sys/kernel/random/boot_id: enabled; else: disabled - private long pause_snapshots_until = 0; // unix time until snapshots are allowed again + private long pause_snapshots_until = 0; // unix time until snapshots are allowed again [s] // empty in "gui mode" contains mode in "cli mode" public string app_mode = ""; @@ -3587,6 +3587,24 @@ public class Main : GLib.Object{ } } + public void pause_snapshots_for(int time_in_s) { + this.pause_snapshots_until = (long) (GLib.get_real_time() / 1000000) + time_in_s; + this.pause_snapshots_this_boot = ""; + this.save_app_config(); + } + + public void pause_snapshots_for_this_boot() { + this.pause_snapshots_until = 0; + this.pause_snapshots_this_boot = TeeJee.System.get_current_boot_id(); + this.save_app_config(); + } + + public void unpause_snpashots() { + this.pause_snapshots_until = 0; + this.pause_snapshots_this_boot = ""; + this.save_app_config(); + } + public void set_first_run_flag(){ first_run = true; diff --git a/src/Gtk/MainWindow.vala b/src/Gtk/MainWindow.vala index cd127b1d..5e88d7ee 100644 --- a/src/Gtk/MainWindow.vala +++ b/src/Gtk/MainWindow.vala @@ -44,7 +44,6 @@ class MainWindow : Gtk.Window{ private Gtk.ToolButton btn_browse_snapshot; private Gtk.ToolButton btn_settings; private Gtk.ToolButton btn_wizard; - private Gtk.Menu menu_extra; private SnapshotListBox snapshot_list_box; @@ -209,9 +208,7 @@ class MainWindow : Gtk.Window{ toolbar.add(button); // click event - button.clicked.connect(()=>{ - menu_extra_popup(null); - }); + button.clicked.connect(() => menu_extra_popup()); } private void init_ui_snapshot_list(){ @@ -357,47 +354,73 @@ class MainWindow : Gtk.Window{ // TODO: low: refresh device list automatically when a device is plugged in } - private bool menu_extra_popup(Gdk.EventButton? event){ + private bool menu_extra_popup(){ - menu_extra = new Gtk.Menu(); + Gtk.Menu? menu_extra = new Gtk.Menu(); menu_extra.reserve_toggle_size = false; Gtk.MenuItem menu_item = null; if (!App.live_system()){ // app logs - menu_item = create_menu_item(_("View TimeShift Logs"), "", "", 16); + menu_item = create_menu_item(_("View TimeShift Logs")); menu_extra.append(menu_item); menu_item.activate.connect(btn_view_app_logs_clicked); + + // pause snapshots + menu_item = create_menu_item(_("Pause Snapshots")); + menu_extra.append(menu_item); + + Gtk.Menu? menu_pause = new Gtk.Menu(); + Gtk.MenuItem? menu_pause_item = create_menu_item(_("Pause for 30min")); + menu_pause_item.activate.connect(() => App.pause_snapshots_for(1800)); + menu_pause.append(menu_pause_item); + + menu_pause_item = create_menu_item(_("Pause for 4h")); + menu_pause_item.activate.connect(() => App.pause_snapshots_for(3600*4)); + menu_pause.append(menu_pause_item); + + menu_pause_item = create_menu_item(_("Pause for 8h")); + menu_pause_item.activate.connect(() => App.pause_snapshots_for(3600*8)); + menu_pause.append(menu_pause_item); + + menu_pause_item = create_menu_item(_("Pause for 12h")); + menu_pause_item.activate.connect(() => App.pause_snapshots_for(3600*12)); + menu_pause.append(menu_pause_item); + + menu_pause_item = create_menu_item(_("Pause until shutdown")); + menu_pause_item.activate.connect(() => App.pause_snapshots_for_this_boot()); + menu_pause.append(menu_pause_item); + + menu_pause_item = create_menu_item(_("Unpause")); + menu_pause_item.activate.connect(() => App.unpause_snpashots()); + menu_pause.append(menu_pause_item); + + menu_pause_item.sensitive = App.snapshots_paused; + + menu_item.submenu = menu_pause; } // about - menu_item = create_menu_item(_("About"), "", "", 16); + menu_item = create_menu_item(_("About")); 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); - } - else { - menu_extra.popup (null, null, null, 0, Gtk.get_current_event_time()); - } + + menu_extra.popup (null, null, null, 0, Gtk.get_current_event_time()); return true; } - 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(); + private Gtk.MenuItem create_menu_item(string label_text, string tooltip_text = ""){ + + Gtk.MenuItem menu_item = new Gtk.MenuItem(); - var box = new Gtk.Box(Orientation.HORIZONTAL, 3); + Gtk.Box box = new Gtk.Box(Orientation.HORIZONTAL, 3); menu_item.add(box); - var label = new Gtk.Label(label_text); + Gtk.Label label = new Gtk.Label(label_text); label.xalign = (float) 0.0; label.margin_end = 6; label.set_tooltip_text((tooltip_text.length > 0) ? tooltip_text : label_text);