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.
This commit is contained in:
x3
2026-09-08 09:52:39 +00:00
parent fac309ece4
commit c08d28b90c
+57 -12
View File
@@ -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) { g_signal_connect_data(restore_item, "activate", G_CALLBACK(+[](GtkWidget*, gpointer d) {
auto* c = static_cast<RestoreCtx*>(d); auto* c = static_cast<RestoreCtx*>(d);
c->self->show_sudo_dialog([c](const std::string& pw) { c->self->show_sudo_dialog([c](const std::string& pw) {
std::vector<std::string> files = {c->path}; struct Ctx { MainWindow* self; std::string path; std::string password; };
c->self->snapshots_.restore_selected(c->self->current_snapshot_, files, pw); auto* ctx = new Ctx{c->self, c->path, pw};
c->self->tray_.show_notification("x3-Backup", "File restored: " + c->path); g_thread_new("restore", [](gpointer data) -> gpointer {
auto* cx = static_cast<Ctx*>(data);
std::vector<std::string> 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<Ctx*>(d);
cx2->self->tray_.show_notification("x3-Backup", "File restored: " + cx2->path);
delete cx2;
return G_SOURCE_REMOVE;
}, cx);
return nullptr;
}, ctx);
}); });
delete c; delete c;
}), ctx, nullptr, (GConnectFlags)0); }), 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) { g_signal_connect_data(restore_item, "activate", G_CALLBACK(+[](GtkWidget*, gpointer d) {
auto* c = static_cast<RestoreCtx*>(d); auto* c = static_cast<RestoreCtx*>(d);
c->self->show_sudo_dialog([c](const std::string& pw) { c->self->show_sudo_dialog([c](const std::string& pw) {
std::vector<std::string> files = {c->path}; struct Ctx { MainWindow* self; std::string path; std::string password; };
c->self->snapshots_.restore_selected(c->self->current_snapshot_, files, pw); auto* ctx = new Ctx{c->self, c->path, pw};
c->self->tray_.show_notification("x3-Backup", "Directory restored: " + c->path); g_thread_new("restore", [](gpointer data) -> gpointer {
auto* cx = static_cast<Ctx*>(data);
std::vector<std::string> 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<Ctx*>(d);
cx2->self->tray_.show_notification("x3-Backup", "Directory restored: " + cx2->path);
delete cx2;
return G_SOURCE_REMOVE;
}, cx);
return nullptr;
}, ctx);
}); });
delete c; delete c;
}), ctx, nullptr, (GConnectFlags)0); }), ctx, nullptr, (GConnectFlags)0);
@@ -939,11 +961,23 @@ void MainWindow::on_restore(GtkWidget*, gpointer d) {
g_free(name); g_free(name);
self->show_sudo_dialog([self, file_path](const std::string& pw) { self->show_sudo_dialog([self, file_path](const std::string& pw) {
std::vector<std::string> files = {file_path};
self->tray_.set_status("x3-Backup - Restoring...", true); self->tray_.set_status("x3-Backup - Restoring...", true);
self->snapshots_.restore_selected(self->current_snapshot_, files, pw);
self->tray_.set_status("x3-Backup - Idle"); struct RestoreCtx { MainWindow* self; std::string file_path; std::string password; };
self->tray_.show_notification("x3-Backup", "Restored: " + file_path); auto* ctx = new RestoreCtx{self, file_path, pw};
g_thread_new("restore", [](gpointer data) -> gpointer {
auto* c = static_cast<RestoreCtx*>(data);
std::vector<std::string> 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<RestoreCtx*>(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->show_sudo_dialog([self](const std::string& pw) {
self->snapshots_.restore_full(self->current_snapshot_, pw); struct SysRestoreCtx { MainWindow* self; std::string password; };
self->tray_.show_notification("x3-Backup", "Full system restore completed"); auto* ctx = new SysRestoreCtx{self, pw};
g_thread_new("sysrestore", [](gpointer data) -> gpointer {
auto* cx = static_cast<SysRestoreCtx*>(data);
cx->self->snapshots_.restore_full(cx->self->current_snapshot_, cx->password);
g_idle_add([](gpointer d) -> gboolean {
auto* cx2 = static_cast<SysRestoreCtx*>(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); gtk_widget_destroy(dialog);