fix: backup progress window + real-time rsync output
- Replace small popup with big backup progress window (750x500) - Shows rsync command in header, real-time output in monospace textview - Progress bar with percentage, Cancel/Close button - Output with color-coded tags (error=red, success=green, cmd=gray italic) - Auto-scrolls to bottom during backup - Fixed live log not updating (stdbuf -oL for unbuffered rsync output) - Fixed double closing brace compilation error - Downloaded proper backup icon
This commit is contained in:
Vendored
+2689
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 18 KiB |
+194
-43
@@ -43,42 +43,65 @@ MainWindow::MainWindow(Config& config)
|
|||||||
auto* ctx = static_cast<Ctx*>(data);
|
auto* ctx = static_cast<Ctx*>(data);
|
||||||
auto* self = ctx->self;
|
auto* self = ctx->self;
|
||||||
const RsyncProgress& p = ctx->prog;
|
const RsyncProgress& p = ctx->prog;
|
||||||
if (self->progress_bar_) {
|
|
||||||
|
/* Update backup progress window */
|
||||||
|
if (self->backup_win_) {
|
||||||
if (p.bytes_total > 0) {
|
if (p.bytes_total > 0) {
|
||||||
double frac = (double)p.bytes_transferred / p.bytes_total;
|
double frac = (double)p.bytes_transferred / p.bytes_total;
|
||||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->progress_bar_), frac);
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->backup_progress_), frac);
|
||||||
}
|
char pct[32];
|
||||||
if (!p.current_file.empty()) {
|
snprintf(pct, sizeof(pct), "%.0f%%", frac * 100);
|
||||||
std::string label = "Syncing: " + p.current_file;
|
gtk_label_set_text(GTK_LABEL(self->backup_status_label_), pct);
|
||||||
gtk_label_set_text(GTK_LABEL(self->progress_label_), label.c_str());
|
|
||||||
gtk_label_set_text(GTK_LABEL(self->live_log_label_), label.c_str());
|
|
||||||
}
|
}
|
||||||
if (!p.log_line.empty()) {
|
if (!p.log_line.empty()) {
|
||||||
const char* tag = nullptr;
|
const char* tag = nullptr;
|
||||||
if (p.log_line.find("[error]") != std::string::npos) tag = "error";
|
if (p.log_line.find("[error]") != std::string::npos) tag = "error";
|
||||||
else if (p.log_line.find("[done]") != std::string::npos) tag = "success";
|
else if (p.log_line.find("[done]") != std::string::npos || p.log_line.find("completed") != std::string::npos) tag = "success";
|
||||||
else if (p.log_line.find("[cmd]") != std::string::npos) tag = "info";
|
else if (p.log_line.find("[cmd]") != std::string::npos) {
|
||||||
|
tag = "cmd";
|
||||||
|
/* Show the rsync command in the header */
|
||||||
|
std::string cmd_display = p.log_line;
|
||||||
|
if (cmd_display.find("[cmd] ") == 0) cmd_display = cmd_display.substr(6);
|
||||||
|
gtk_label_set_text(GTK_LABEL(self->backup_cmd_label_), cmd_display.c_str());
|
||||||
|
}
|
||||||
else if (p.log_line.find("[restore") != std::string::npos) tag = "info";
|
else if (p.log_line.find("[restore") != std::string::npos) tag = "info";
|
||||||
self->append_live_log(p.log_line, tag);
|
self->append_backup_line(p.log_line, tag);
|
||||||
}
|
}
|
||||||
if (p.finished) {
|
if (p.finished) {
|
||||||
if (self->progress_window_) {
|
|
||||||
gtk_widget_destroy(self->progress_window_);
|
|
||||||
self->progress_window_ = nullptr;
|
|
||||||
}
|
|
||||||
self->refresh_snapshot_list();
|
|
||||||
if (p.error) {
|
if (p.error) {
|
||||||
self->append_live_log("[ERROR] " + p.error_message, "error");
|
self->append_backup_line("[ERROR] " + p.error_message, "error");
|
||||||
self->tray_.show_notification("x3-Backup", p.error_message, true);
|
self->tray_.show_notification("x3-Backup", p.error_message, true);
|
||||||
gtk_label_set_text(GTK_LABEL(self->live_log_label_), "Backup failed");
|
gtk_label_set_text(GTK_LABEL(self->backup_status_label_), "Failed");
|
||||||
|
gtk_button_set_label(GTK_BUTTON(self->backup_cancel_btn_), "Close");
|
||||||
} else {
|
} else {
|
||||||
self->append_live_log("[SUCCESS] Backup completed", "success");
|
self->append_backup_line("[SUCCESS] Backup completed!", "success");
|
||||||
self->tray_.show_notification("x3-Backup", "Backup completed successfully");
|
self->tray_.show_notification("x3-Backup", "Backup completed successfully");
|
||||||
gtk_label_set_text(GTK_LABEL(self->live_log_label_), "Backup completed");
|
gtk_label_set_text(GTK_LABEL(self->backup_status_label_), "Done");
|
||||||
|
gtk_button_set_label(GTK_BUTTON(self->backup_cancel_btn_), "Close");
|
||||||
}
|
}
|
||||||
self->tray_.set_status("x3-Backup - Idle");
|
self->tray_.set_status("x3-Backup - Idle");
|
||||||
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(self->backup_progress_), 1.0);
|
||||||
|
self->refresh_snapshot_list();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Also update live log tab */
|
||||||
|
if (!p.log_line.empty()) {
|
||||||
|
const char* tag = nullptr;
|
||||||
|
if (p.log_line.find("[error]") != std::string::npos) tag = "error";
|
||||||
|
else if (p.log_line.find("[done]") != std::string::npos) tag = "success";
|
||||||
|
else if (p.log_line.find("[cmd]") != std::string::npos) tag = "info";
|
||||||
|
else if (p.log_line.find("[restore") != std::string::npos) tag = "info";
|
||||||
|
self->append_live_log(p.log_line, tag);
|
||||||
|
}
|
||||||
|
if (p.finished) {
|
||||||
|
if (p.error) {
|
||||||
|
gtk_label_set_text(GTK_LABEL(self->live_log_label_), "Backup failed");
|
||||||
|
} else {
|
||||||
|
gtk_label_set_text(GTK_LABEL(self->live_log_label_), "Backup completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
delete ctx;
|
delete ctx;
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}, ctx);
|
}, ctx);
|
||||||
@@ -406,12 +429,6 @@ void MainWindow::build_toolbar() {
|
|||||||
gtk_box_pack_start(GTK_BOX(tbar), gtk_separator_new(GTK_ORIENTATION_VERTICAL), FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(tbar), gtk_separator_new(GTK_ORIENTATION_VERTICAL), FALSE, FALSE, 0);
|
||||||
gtk_box_pack_start(GTK_BOX(tbar), mkbtn("Settings", G_CALLBACK(on_settings), this), FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(tbar), mkbtn("Settings", G_CALLBACK(on_settings), this), FALSE, FALSE, 0);
|
||||||
|
|
||||||
progress_bar_ = gtk_progress_bar_new();
|
|
||||||
gtk_widget_set_size_request(progress_bar_, 200, -1);
|
|
||||||
gtk_box_pack_end(GTK_BOX(tbar), progress_bar_, FALSE, FALSE, 0);
|
|
||||||
progress_label_ = gtk_label_new("");
|
|
||||||
gtk_box_pack_end(GTK_BOX(tbar), progress_label_, FALSE, FALSE, 4);
|
|
||||||
|
|
||||||
gtk_box_pack_start(GTK_BOX(toolbar_), tbar, FALSE, FALSE, 0);
|
gtk_box_pack_start(GTK_BOX(toolbar_), tbar, FALSE, FALSE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,34 +667,168 @@ void MainWindow::show_sudo_dialog(std::function<void(const std::string&)> callba
|
|||||||
gtk_widget_destroy(dialog);
|
gtk_widget_destroy(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::show_progress_dialog(const std::string& title) {
|
void MainWindow::open_backup_window(const std::string& description) {
|
||||||
progress_window_ = gtk_window_new(GTK_WINDOW_POPUP);
|
if (backup_win_) {
|
||||||
gtk_window_set_title(GTK_WINDOW(progress_window_), title.c_str());
|
/* Clear previous output */
|
||||||
gtk_window_set_default_size(GTK_WINDOW(progress_window_), 400, 120);
|
GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(backup_output_view_));
|
||||||
gtk_window_set_position(GTK_WINDOW(progress_window_), GTK_WIN_POS_CENTER);
|
gtk_text_buffer_set_text(buf, "", -1);
|
||||||
gtk_window_set_keep_above(GTK_WINDOW(progress_window_), TRUE);
|
gtk_label_set_text(GTK_LABEL(backup_cmd_label_), "");
|
||||||
|
gtk_label_set_text(GTK_LABEL(backup_status_label_), "Running...");
|
||||||
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(backup_progress_), 0.0);
|
||||||
|
gtk_button_set_label(GTK_BUTTON(backup_cancel_btn_), "Cancel");
|
||||||
|
gtk_widget_show_all(backup_win_);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 8);
|
backup_win_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||||
gtk_widget_set_margin_start(vbox, 16);
|
gtk_window_set_title(GTK_WINDOW(backup_win_), "x3-Backup - Backup Progress");
|
||||||
gtk_widget_set_margin_top(vbox, 16);
|
gtk_window_set_default_size(GTK_WINDOW(backup_win_), 750, 500);
|
||||||
gtk_container_add(GTK_CONTAINER(progress_window_), vbox);
|
gtk_window_set_position(GTK_WINDOW(backup_win_), GTK_WIN_POS_CENTER);
|
||||||
|
gtk_window_set_transient_for(GTK_WINDOW(backup_win_), GTK_WINDOW(window_));
|
||||||
|
gtk_window_set_modal(GTK_WINDOW(backup_win_), TRUE);
|
||||||
|
|
||||||
GtkWidget* label = gtk_label_new(title.c_str());
|
const char* icon_paths[] = {
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
|
"icons/x3-backup.png",
|
||||||
|
"/usr/share/icons/hicolor/256x256/apps/x3-backup.png",
|
||||||
|
nullptr
|
||||||
|
};
|
||||||
|
for (int i = 0; icon_paths[i]; ++i) {
|
||||||
|
if (g_file_test(icon_paths[i], G_FILE_TEST_EXISTS)) {
|
||||||
|
gtk_window_set_icon_from_file(GTK_WINDOW(backup_win_), icon_paths[i], nullptr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
progress_bar_ = gtk_progress_bar_new();
|
GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), progress_bar_, FALSE, FALSE, 0);
|
gtk_widget_set_margin_start(vbox, 8);
|
||||||
|
gtk_widget_set_margin_end(vbox, 8);
|
||||||
|
gtk_widget_set_margin_top(vbox, 8);
|
||||||
|
gtk_widget_set_margin_bottom(vbox, 8);
|
||||||
|
gtk_container_add(GTK_CONTAINER(backup_win_), vbox);
|
||||||
|
|
||||||
progress_label_ = gtk_label_new("Starting...");
|
/* Header */
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), progress_label_, FALSE, FALSE, 0);
|
GtkWidget* hdr_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||||
|
GtkWidget* hdr_icon = gtk_image_new_from_icon_name("drive-harddisk", GTK_ICON_SIZE_DIALOG);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hdr_box), hdr_icon, FALSE, FALSE, 0);
|
||||||
|
|
||||||
gtk_widget_show_all(progress_window_);
|
GtkWidget* hdr_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
|
||||||
|
std::string title_text = description.empty() ? "Creating Backup..." : description;
|
||||||
|
GtkWidget* hdr_title = gtk_label_new(nullptr);
|
||||||
|
char title_markup[512];
|
||||||
|
snprintf(title_markup, sizeof(title_markup), "<b><big>%s</big></big>", title_text.c_str());
|
||||||
|
gtk_label_set_markup(GTK_LABEL(hdr_title), title_markup);
|
||||||
|
gtk_widget_set_halign(hdr_title, GTK_ALIGN_START);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hdr_vbox), hdr_title, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
backup_cmd_label_ = gtk_label_new("Waiting for rsync...");
|
||||||
|
gtk_widget_set_halign(backup_cmd_label_, GTK_ALIGN_START);
|
||||||
|
PangoAttrList* mono = pango_attr_list_new();
|
||||||
|
pango_attr_list_insert(mono, pango_attr_family_new("monospace"));
|
||||||
|
pango_attr_list_insert(mono, pango_attr_size_new(8000));
|
||||||
|
gtk_label_set_attributes(GTK_LABEL(backup_cmd_label_), mono);
|
||||||
|
pango_attr_list_unref(mono);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hdr_vbox), backup_cmd_label_, FALSE, FALSE, 0);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hdr_box), hdr_vbox, TRUE, TRUE, 0);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), hdr_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
/* rsync output */
|
||||||
|
GtkWidget* output_scroll = gtk_scrolled_window_new(nullptr, nullptr);
|
||||||
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(output_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||||
|
backup_output_view_ = gtk_text_view_new();
|
||||||
|
gtk_text_view_set_editable(GTK_TEXT_VIEW(backup_output_view_), FALSE);
|
||||||
|
gtk_text_view_set_monospace(GTK_TEXT_VIEW(backup_output_view_), TRUE);
|
||||||
|
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(backup_output_view_), GTK_WRAP_WORD_CHAR);
|
||||||
|
|
||||||
|
/* Color tags */
|
||||||
|
GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(backup_output_view_));
|
||||||
|
gtk_text_buffer_create_tag(buf, "error", "foreground", "#e74c3c", "weight", PANGO_WEIGHT_BOLD, nullptr);
|
||||||
|
gtk_text_buffer_create_tag(buf, "success", "foreground", "#2ecc71", "weight", PANGO_WEIGHT_BOLD, nullptr);
|
||||||
|
gtk_text_buffer_create_tag(buf, "info", "foreground", "#3498db", nullptr);
|
||||||
|
gtk_text_buffer_create_tag(buf, "cmd", "foreground", "#95a5a6", "style", PANGO_STYLE_ITALIC, nullptr);
|
||||||
|
|
||||||
|
gtk_container_add(GTK_CONTAINER(output_scroll), backup_output_view_);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), output_scroll, TRUE, TRUE, 0);
|
||||||
|
|
||||||
|
/* Progress bar + status */
|
||||||
|
GtkWidget* prog_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||||
|
backup_progress_ = gtk_progress_bar_new();
|
||||||
|
gtk_widget_set_hexpand(backup_progress_, TRUE);
|
||||||
|
gtk_box_pack_start(GTK_BOX(prog_box), backup_progress_, TRUE, TRUE, 0);
|
||||||
|
backup_status_label_ = gtk_label_new("Running...");
|
||||||
|
gtk_box_pack_start(GTK_BOX(prog_box), backup_status_label_, FALSE, FALSE, 0);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), prog_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
GtkWidget* btn_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||||
|
gtk_widget_set_halign(btn_box, GTK_ALIGN_END);
|
||||||
|
|
||||||
|
backup_cancel_btn_ = gtk_button_new_with_label("Cancel");
|
||||||
|
g_signal_connect(backup_cancel_btn_, "clicked", G_CALLBACK(+[](GtkWidget*, gpointer d) {
|
||||||
|
auto* self = static_cast<MainWindow*>(d);
|
||||||
|
const char* label = gtk_button_get_label(GTK_BUTTON(self->backup_cancel_btn_));
|
||||||
|
if (strcmp(label, "Close") == 0) {
|
||||||
|
self->close_backup_window();
|
||||||
|
} else {
|
||||||
|
self->rsync_.cancel();
|
||||||
|
gtk_label_set_text(GTK_LABEL(self->backup_status_label_), "Cancelling...");
|
||||||
|
gtk_button_set_label(GTK_BUTTON(self->backup_cancel_btn_), "Close");
|
||||||
|
}
|
||||||
|
}), this);
|
||||||
|
gtk_box_pack_start(GTK_BOX(btn_box), backup_cancel_btn_, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), btn_box, FALSE, FALSE, 0);
|
||||||
|
|
||||||
|
g_signal_connect(backup_win_, "delete-event", G_CALLBACK(+[](GtkWidget*, GdkEvent*, gpointer d) -> gboolean {
|
||||||
|
auto* self = static_cast<MainWindow*>(d);
|
||||||
|
if (self->rsync_.is_running()) {
|
||||||
|
/* Don't close while running, just hide */
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
self->close_backup_window();
|
||||||
|
return TRUE;
|
||||||
|
}), this);
|
||||||
|
|
||||||
|
gtk_widget_show_all(backup_win_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::close_backup_window() {
|
||||||
|
if (backup_win_) {
|
||||||
|
gtk_widget_destroy(backup_win_);
|
||||||
|
backup_win_ = nullptr;
|
||||||
|
backup_output_view_ = nullptr;
|
||||||
|
backup_cmd_label_ = nullptr;
|
||||||
|
backup_progress_ = nullptr;
|
||||||
|
backup_status_label_ = nullptr;
|
||||||
|
backup_cancel_btn_ = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::append_backup_line(const std::string& line, const char* tag) {
|
||||||
|
if (!backup_output_view_) return;
|
||||||
|
GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(backup_output_view_));
|
||||||
|
GtkTextIter end;
|
||||||
|
gtk_text_buffer_get_end_iter(buf, &end);
|
||||||
|
if (tag) {
|
||||||
|
gtk_text_buffer_insert_with_tags_by_name(buf, &end, line.c_str(), -1, tag);
|
||||||
|
} else {
|
||||||
|
gtk_text_buffer_insert(buf, &end, line.c_str(), -1);
|
||||||
|
}
|
||||||
|
gtk_text_buffer_insert(buf, &end, "\n", -1);
|
||||||
|
|
||||||
|
/* Auto-scroll */
|
||||||
|
GtkTextView* tv = GTK_TEXT_VIEW(backup_output_view_);
|
||||||
|
GtkTextMark* mark = gtk_text_buffer_create_mark(buf, nullptr, &end, FALSE);
|
||||||
|
gtk_text_view_scroll_mark_onscreen(tv, mark);
|
||||||
|
gtk_text_buffer_delete_mark(buf, mark);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_backup(GtkWidget*, gpointer d) {
|
void MainWindow::on_backup(GtkWidget*, gpointer d) {
|
||||||
auto* self = static_cast<MainWindow*>(d);
|
auto* self = static_cast<MainWindow*>(d);
|
||||||
self->tray_.set_status("x3-Backup - Creating backup...", true);
|
self->tray_.set_status("x3-Backup - Creating backup...", true);
|
||||||
self->show_progress_dialog("Creating Snapshot...");
|
self->open_backup_window("Creating Snapshot...");
|
||||||
|
gtk_label_set_text(GTK_LABEL(self->live_log_label_), "Backup running...");
|
||||||
|
|
||||||
g_thread_new("backup", [](gpointer data) -> gpointer {
|
g_thread_new("backup", [](gpointer data) -> gpointer {
|
||||||
auto* s = static_cast<MainWindow*>(data);
|
auto* s = static_cast<MainWindow*>(data);
|
||||||
|
|||||||
+12
-15
@@ -28,22 +28,16 @@ private:
|
|||||||
void build_ui();
|
void build_ui();
|
||||||
void build_menu();
|
void build_menu();
|
||||||
void build_toolbar();
|
void build_toolbar();
|
||||||
void build_sidebar();
|
|
||||||
void build_file_browser();
|
|
||||||
void build_statusbar();
|
void build_statusbar();
|
||||||
|
|
||||||
void refresh_snapshot_list();
|
void refresh_snapshot_list();
|
||||||
void load_selected_snapshot();
|
|
||||||
void browse_path(const std::string& snapshot, const std::string& path);
|
void browse_path(const std::string& snapshot, const std::string& path);
|
||||||
void navigate_up();
|
void navigate_up();
|
||||||
|
|
||||||
void on_backup_clicked();
|
|
||||||
void on_restore_clicked();
|
|
||||||
void on_delete_snapshot_clicked();
|
|
||||||
void on_new_backup_clicked();
|
|
||||||
|
|
||||||
void show_sudo_dialog(std::function<void(const std::string&)> callback);
|
void show_sudo_dialog(std::function<void(const std::string&)> callback);
|
||||||
void show_progress_dialog(const std::string& title);
|
void open_backup_window(const std::string& description = "");
|
||||||
|
void close_backup_window();
|
||||||
|
void append_backup_line(const std::string& line, const char* tag = nullptr);
|
||||||
|
|
||||||
void install_cronjob();
|
void install_cronjob();
|
||||||
void remove_cronjob();
|
void remove_cronjob();
|
||||||
@@ -80,22 +74,25 @@ private:
|
|||||||
GtkWidget* file_tree_ = nullptr;
|
GtkWidget* file_tree_ = nullptr;
|
||||||
GtkWidget* path_entry_ = nullptr;
|
GtkWidget* path_entry_ = nullptr;
|
||||||
GtkWidget* statusbar_ = nullptr;
|
GtkWidget* statusbar_ = nullptr;
|
||||||
GtkWidget* progress_bar_ = nullptr;
|
|
||||||
GtkWidget* progress_label_ = nullptr;
|
|
||||||
GtkWidget* progress_window_ = nullptr;
|
|
||||||
GtkWidget* nav_label_ = nullptr;
|
GtkWidget* nav_label_ = nullptr;
|
||||||
|
|
||||||
GtkListStore* file_store_ = nullptr;
|
GtkListStore* file_store_ = nullptr;
|
||||||
GtkWidget* toolbar_ = nullptr;
|
GtkWidget* toolbar_ = nullptr;
|
||||||
GtkWidget* log_window_ = nullptr;
|
|
||||||
GtkWidget* log_textview_ = nullptr;
|
|
||||||
guint log_timer_ = 0;
|
|
||||||
|
|
||||||
GtkWidget* live_log_textview_ = nullptr;
|
GtkWidget* live_log_textview_ = nullptr;
|
||||||
GtkWidget* live_log_label_ = nullptr;
|
GtkWidget* live_log_label_ = nullptr;
|
||||||
GtkWidget* backlog_textview_ = nullptr;
|
GtkWidget* backlog_textview_ = nullptr;
|
||||||
GtkWidget* backlog_scrolled_ = nullptr;
|
GtkWidget* backlog_scrolled_ = nullptr;
|
||||||
|
|
||||||
|
/* Backup progress window */
|
||||||
|
GtkWidget* backup_win_ = nullptr;
|
||||||
|
GtkWidget* backup_cmd_label_ = nullptr;
|
||||||
|
GtkWidget* backup_output_view_ = nullptr;
|
||||||
|
GtkWidget* backup_progress_ = nullptr;
|
||||||
|
GtkWidget* backup_status_label_ = nullptr;
|
||||||
|
GtkWidget* backup_cancel_btn_ = nullptr;
|
||||||
|
GtkWidget* backup_close_btn_ = nullptr;
|
||||||
|
|
||||||
std::string log_path_;
|
std::string log_path_;
|
||||||
|
|
||||||
std::string current_snapshot_;
|
std::string current_snapshot_;
|
||||||
|
|||||||
@@ -44,7 +44,10 @@ bool RsyncManager::create_snapshot(const std::string& snapshot_name,
|
|||||||
|
|
||||||
cmd += " \"" + source + "/\" \"" + target + "/\" 2>&1";
|
cmd += " \"" + source + "/\" \"" + target + "/\" 2>&1";
|
||||||
|
|
||||||
g_message("rsync cmd: %s", cmd.c_str());
|
/* Force line-buffered output so we get real-time progress from rsync */
|
||||||
|
std::string full_cmd = "stdbuf -oL " + cmd;
|
||||||
|
|
||||||
|
g_message("rsync cmd: %s", full_cmd.c_str());
|
||||||
|
|
||||||
if (on_progress) {
|
if (on_progress) {
|
||||||
RsyncProgress p;
|
RsyncProgress p;
|
||||||
@@ -52,7 +55,7 @@ bool RsyncManager::create_snapshot(const std::string& snapshot_name,
|
|||||||
on_progress(p);
|
on_progress(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* pipe = popen(cmd.c_str(), "r");
|
FILE* pipe = popen(full_cmd.c_str(), "r");
|
||||||
if (!pipe) {
|
if (!pipe) {
|
||||||
running_ = false;
|
running_ = false;
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user