From c08d28b90c385614ede8dbd73ef608ca8c67822c Mon Sep 17 00:00:00 2001 From: x3 Date: Tue, 8 Sep 2026 09:52:39 +0000 Subject: [PATCH] fix: run restore in background thread to prevent GUI crash Restore was blocking the main thread via popen(), causing the GUI to freeze and crash. Now runs rsync in a separate thread like backup. --- src/main_window.cpp | 69 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/src/main_window.cpp b/src/main_window.cpp index 36f83cd..3cc5e2c 100644 --- a/src/main_window.cpp +++ b/src/main_window.cpp @@ -628,9 +628,20 @@ gboolean MainWindow::on_file_button_press(GtkWidget*, GdkEventButton* event, gpo g_signal_connect_data(restore_item, "activate", G_CALLBACK(+[](GtkWidget*, gpointer d) { auto* c = static_cast(d); c->self->show_sudo_dialog([c](const std::string& pw) { - std::vector files = {c->path}; - c->self->snapshots_.restore_selected(c->self->current_snapshot_, files, pw); - c->self->tray_.show_notification("x3-Backup", "File restored: " + c->path); + struct Ctx { MainWindow* self; std::string path; std::string password; }; + auto* ctx = new Ctx{c->self, c->path, pw}; + g_thread_new("restore", [](gpointer data) -> gpointer { + auto* cx = static_cast(data); + std::vector files = {cx->path}; + cx->self->snapshots_.restore_selected(cx->self->current_snapshot_, files, cx->password); + g_idle_add([](gpointer d) -> gboolean { + auto* cx2 = static_cast(d); + cx2->self->tray_.show_notification("x3-Backup", "File restored: " + cx2->path); + delete cx2; + return G_SOURCE_REMOVE; + }, cx); + return nullptr; + }, ctx); }); delete c; }), ctx, nullptr, (GConnectFlags)0); @@ -657,9 +668,20 @@ gboolean MainWindow::on_file_button_press(GtkWidget*, GdkEventButton* event, gpo g_signal_connect_data(restore_item, "activate", G_CALLBACK(+[](GtkWidget*, gpointer d) { auto* c = static_cast(d); c->self->show_sudo_dialog([c](const std::string& pw) { - std::vector files = {c->path}; - c->self->snapshots_.restore_selected(c->self->current_snapshot_, files, pw); - c->self->tray_.show_notification("x3-Backup", "Directory restored: " + c->path); + struct Ctx { MainWindow* self; std::string path; std::string password; }; + auto* ctx = new Ctx{c->self, c->path, pw}; + g_thread_new("restore", [](gpointer data) -> gpointer { + auto* cx = static_cast(data); + std::vector files = {cx->path}; + cx->self->snapshots_.restore_selected(cx->self->current_snapshot_, files, cx->password); + g_idle_add([](gpointer d) -> gboolean { + auto* cx2 = static_cast(d); + cx2->self->tray_.show_notification("x3-Backup", "Directory restored: " + cx2->path); + delete cx2; + return G_SOURCE_REMOVE; + }, cx); + return nullptr; + }, ctx); }); delete c; }), ctx, nullptr, (GConnectFlags)0); @@ -939,11 +961,23 @@ void MainWindow::on_restore(GtkWidget*, gpointer d) { g_free(name); self->show_sudo_dialog([self, file_path](const std::string& pw) { - std::vector files = {file_path}; self->tray_.set_status("x3-Backup - Restoring...", true); - self->snapshots_.restore_selected(self->current_snapshot_, files, pw); - self->tray_.set_status("x3-Backup - Idle"); - self->tray_.show_notification("x3-Backup", "Restored: " + file_path); + + struct RestoreCtx { MainWindow* self; std::string file_path; std::string password; }; + auto* ctx = new RestoreCtx{self, file_path, pw}; + g_thread_new("restore", [](gpointer data) -> gpointer { + auto* c = static_cast(data); + std::vector files = {c->file_path}; + c->self->snapshots_.restore_selected(c->self->current_snapshot_, files, c->password); + g_idle_add([](gpointer d) -> gboolean { + auto* c2 = static_cast(d); + c2->self->tray_.set_status("x3-Backup - Idle"); + c2->self->tray_.show_notification("x3-Backup", "Restored: " + c2->file_path); + delete c2; + return G_SOURCE_REMOVE; + }, c); + return nullptr; + }, ctx); }); } @@ -1067,8 +1101,19 @@ void MainWindow::on_system_restore(GtkWidget*, gpointer d) { } self->show_sudo_dialog([self](const std::string& pw) { - self->snapshots_.restore_full(self->current_snapshot_, pw); - self->tray_.show_notification("x3-Backup", "Full system restore completed"); + struct SysRestoreCtx { MainWindow* self; std::string password; }; + auto* ctx = new SysRestoreCtx{self, pw}; + g_thread_new("sysrestore", [](gpointer data) -> gpointer { + auto* cx = static_cast(data); + cx->self->snapshots_.restore_full(cx->self->current_snapshot_, cx->password); + g_idle_add([](gpointer d) -> gboolean { + auto* cx2 = static_cast(d); + cx2->self->tray_.show_notification("x3-Backup", "Full system restore completed"); + delete cx2; + return G_SOURCE_REMOVE; + }, cx); + return nullptr; + }, ctx); }); } gtk_widget_destroy(dialog);