feat: server list sidebar + notifications + new icon
- Added server list sidebar (GtkPaned) showing saved servers with name, user@host:port detail. Double-click to connect. - Added '+' button in sidebar to add new servers - Added notification bar (animated GtkRevealer) for status messages: 'Server saved', 'Server connected', 'Server disconnected', 'Server removed', 'Key generated', 'Key imported', 'Key deleted' Auto-hides after 4 seconds. - Changed icon to terminal-style PNG + SVG (scalable) - Server list updates automatically when servers are added/removed Layout: [Sidebar: Servers] | [Notebook: Terminal Tabs]
This commit is contained in:
+169
-34
@@ -15,21 +15,36 @@ static void clear_container(GtkWidget* container) {
|
||||
g_list_free(children);
|
||||
}
|
||||
|
||||
static void refresh_server_list(GtkWidget* listbox, const std::vector<ServerConfig>& servers) {
|
||||
static void refresh_server_list_widget(GtkWidget* listbox, const std::vector<ServerConfig>& servers) {
|
||||
clear_container(listbox);
|
||||
for (const auto& s : servers) {
|
||||
std::string text = s.name + " | " + s.user + "@" + s.host + ":" + std::to_string(s.port);
|
||||
if (s.use_key) text += " [key]";
|
||||
GtkWidget* row = gtk_label_new(text.c_str());
|
||||
gtk_widget_set_halign(row, GTK_ALIGN_START);
|
||||
gtk_widget_set_margin_start(row, 8);
|
||||
gtk_widget_set_margin_top(row, 4);
|
||||
gtk_widget_set_margin_bottom(row, 4);
|
||||
gtk_list_box_insert(GTK_LIST_BOX(listbox), row, -1);
|
||||
GtkWidget* row_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 2);
|
||||
gtk_widget_set_margin_start(row_box, 8);
|
||||
gtk_widget_set_margin_end(row_box, 8);
|
||||
gtk_widget_set_margin_top(row_box, 6);
|
||||
gtk_widget_set_margin_bottom(row_box, 6);
|
||||
|
||||
GtkWidget* name_label = gtk_label_new(s.name.c_str());
|
||||
gtk_widget_set_halign(name_label, GTK_ALIGN_START);
|
||||
gtk_label_set_ellipsize(GTK_LABEL(name_label), PANGO_ELLIPSIZE_END);
|
||||
PangoAttrList* attrs = pango_attr_list_new();
|
||||
pango_attr_list_insert(attrs, pango_attr_weight_new(PANGO_WEIGHT_BOLD));
|
||||
gtk_label_set_attributes(GTK_LABEL(name_label), attrs);
|
||||
pango_attr_list_unref(attrs);
|
||||
gtk_box_pack_start(GTK_BOX(row_box), name_label, FALSE, FALSE, 0);
|
||||
|
||||
std::string detail = s.user + "@" + s.host + ":" + std::to_string(s.port);
|
||||
if (s.use_key) detail += " [key]";
|
||||
GtkWidget* detail_label = gtk_label_new(detail.c_str());
|
||||
gtk_widget_set_halign(detail_label, GTK_ALIGN_START);
|
||||
gtk_label_set_ellipsize(GTK_LABEL(detail_label), PANGO_ELLIPSIZE_END);
|
||||
gtk_box_pack_start(GTK_BOX(row_box), detail_label, FALSE, FALSE, 0);
|
||||
|
||||
gtk_list_box_insert(GTK_LIST_BOX(listbox), row_box, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void refresh_key_list(GtkWidget* listbox, const std::vector<SshKey>& keys) {
|
||||
static void refresh_key_list_widget(GtkWidget* listbox, const std::vector<SshKey>& keys) {
|
||||
clear_container(listbox);
|
||||
for (const auto& k : keys) {
|
||||
std::string text = k.name + " | " + k.fingerprint;
|
||||
@@ -47,7 +62,9 @@ static void refresh_key_list(GtkWidget* listbox, const std::vector<SshKey>& keys
|
||||
SshClientWindow::SshClientWindow()
|
||||
: window_(nullptr), notebook_(nullptr), statusbar_(nullptr),
|
||||
server_combo_(nullptr), quick_entry_(nullptr),
|
||||
user_entry_(nullptr), port_spin_(nullptr) {
|
||||
user_entry_(nullptr), port_spin_(nullptr),
|
||||
server_listbox_(nullptr), notif_revealer_(nullptr),
|
||||
notif_label_(nullptr), notif_bar_(nullptr) {
|
||||
build_ui();
|
||||
}
|
||||
|
||||
@@ -81,15 +98,45 @@ void SshClientWindow::build_ui() {
|
||||
}
|
||||
}
|
||||
|
||||
GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(window_), vbox);
|
||||
GtkWidget* main_vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add(GTK_CONTAINER(window_), main_vbox);
|
||||
|
||||
/* ── notification bar (top, hidden by default) ── */
|
||||
notif_bar_ = gtk_revealer_new();
|
||||
gtk_revealer_set_transition_type(GTK_REVEALER(notif_bar_), GTK_REVEALER_TRANSITION_TYPE_SLIDE_DOWN);
|
||||
gtk_revealer_set_reveal_child(GTK_REVEALER(notif_bar_), FALSE);
|
||||
GtkWidget* notif_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
|
||||
gtk_widget_set_margin_start(notif_box, 12);
|
||||
gtk_widget_set_margin_end(notif_box, 12);
|
||||
gtk_widget_set_margin_top(notif_box, 6);
|
||||
gtk_widget_set_margin_bottom(notif_box, 6);
|
||||
notif_label_ = gtk_label_new("");
|
||||
gtk_widget_set_halign(notif_label_, GTK_ALIGN_START);
|
||||
gtk_widget_set_hexpand(notif_label_, TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(notif_box), notif_label_, TRUE, TRUE, 0);
|
||||
GtkWidget* notif_close = gtk_button_new_from_icon_name("window-close", GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_set_size_request(notif_close, 24, 24);
|
||||
g_signal_connect(notif_close, "clicked", G_CALLBACK(+[](GtkWidget*, gpointer d) {
|
||||
gtk_revealer_set_reveal_child(GTK_REVEALER(d), FALSE);
|
||||
}), notif_bar_);
|
||||
gtk_box_pack_end(GTK_BOX(notif_box), notif_close, FALSE, FALSE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(notif_bar_), notif_box);
|
||||
/* colored background */
|
||||
GtkCssProvider* css = gtk_css_provider_new();
|
||||
gtk_css_provider_load_from_data(css, ".notif-ok { background: #2ecc71; color: #000; }"
|
||||
".notif-err { background: #e74c3c; color: #fff; }", -1, nullptr);
|
||||
GtkStyleContext* ctx = gtk_widget_get_style_context(notif_bar_);
|
||||
gtk_style_context_add_provider(ctx, GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
g_object_unref(css);
|
||||
gtk_box_pack_start(GTK_BOX(main_vbox), notif_bar_, FALSE, FALSE, 0);
|
||||
|
||||
/* ── toolbar ── */
|
||||
GtkWidget* toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
|
||||
gtk_widget_set_margin_start(toolbar, 6);
|
||||
gtk_widget_set_margin_end(toolbar, 6);
|
||||
gtk_widget_set_margin_top(toolbar, 4);
|
||||
gtk_widget_set_margin_bottom(toolbar, 4);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(main_vbox), toolbar, FALSE, FALSE, 0);
|
||||
|
||||
server_combo_ = gtk_combo_box_text_new();
|
||||
gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(server_combo_), 0);
|
||||
@@ -115,20 +162,72 @@ void SshClientWindow::build_ui() {
|
||||
gtk_box_pack_start(GTK_BOX(toolbar), make_button("+ Tab", G_CALLBACK(on_new_tab), this), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(toolbar), make_button("Close Tab", G_CALLBACK(on_close_tab), this), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(toolbar), make_button("Disconnect", G_CALLBACK(on_disconnect), this), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(toolbar), make_button("Servers", G_CALLBACK(on_manage_servers), this), FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(toolbar), make_button("Keys", G_CALLBACK(on_manage_keys), this), FALSE, FALSE, 0);
|
||||
|
||||
update_server_combo();
|
||||
|
||||
GtkWidget* sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), sep, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(main_vbox), sep, FALSE, FALSE, 0);
|
||||
|
||||
/* ── paned: sidebar | notebook ── */
|
||||
GtkWidget* paned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_pack_start(GTK_BOX(main_vbox), paned, TRUE, TRUE, 0);
|
||||
|
||||
/* ── sidebar: server list ── */
|
||||
GtkWidget* sidebar = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_paned_pack1(GTK_PANED(paned), sidebar, FALSE, FALSE);
|
||||
gtk_widget_set_size_request(sidebar, 220, -1);
|
||||
|
||||
GtkWidget* sidebar_header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_margin_start(sidebar_header, 8);
|
||||
gtk_widget_set_margin_end(sidebar_header, 4);
|
||||
gtk_widget_set_margin_top(sidebar_header, 6);
|
||||
gtk_widget_set_margin_bottom(sidebar_header, 6);
|
||||
GtkWidget* sidebar_title = gtk_label_new(nullptr);
|
||||
gtk_label_set_markup(GTK_LABEL(sidebar_title), "<b>Servers</b>");
|
||||
gtk_box_pack_start(GTK_BOX(sidebar_header), sidebar_title, TRUE, TRUE, 0);
|
||||
GtkWidget* add_srv_btn = gtk_button_new_from_icon_name("list-add", GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_set_size_request(add_srv_btn, 28, 28);
|
||||
g_signal_connect(add_srv_btn, "clicked", G_CALLBACK(on_add_server), this);
|
||||
gtk_box_pack_end(GTK_BOX(sidebar_header), add_srv_btn, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(sidebar), sidebar_header, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget* sidebar_sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL);
|
||||
gtk_box_pack_start(GTK_BOX(sidebar), sidebar_sep, FALSE, FALSE, 0);
|
||||
|
||||
GtkWidget* scrolled = gtk_scrolled_window_new(nullptr, nullptr);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
||||
server_listbox_ = gtk_list_box_new();
|
||||
gtk_list_box_set_selection_mode(GTK_LIST_BOX(server_listbox_), GTK_SELECTION_SINGLE);
|
||||
g_signal_connect(server_listbox_, "row-activated", G_CALLBACK(on_server_row_activated), this);
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), server_listbox_);
|
||||
gtk_box_pack_start(GTK_BOX(sidebar), scrolled, TRUE, TRUE, 0);
|
||||
|
||||
update_server_list();
|
||||
|
||||
/* ── notebook for terminals ── */
|
||||
notebook_ = gtk_notebook_new();
|
||||
gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook_), TRUE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), notebook_, TRUE, TRUE, 0);
|
||||
gtk_paned_pack2(GTK_PANED(paned), notebook_, TRUE, TRUE);
|
||||
|
||||
/* ── statusbar ── */
|
||||
statusbar_ = gtk_statusbar_new();
|
||||
gtk_box_pack_end(GTK_BOX(vbox), statusbar_, FALSE, FALSE, 0);
|
||||
gtk_box_pack_end(GTK_BOX(main_vbox), statusbar_, FALSE, FALSE, 0);
|
||||
}
|
||||
|
||||
void SshClientWindow::show_notification(const std::string& msg, bool is_error) {
|
||||
gtk_label_set_text(GTK_LABEL(notif_label_), msg.c_str());
|
||||
GtkStyleContext* ctx = gtk_widget_get_style_context(notif_bar_);
|
||||
gtk_style_context_remove_class(ctx, "notif-ok");
|
||||
gtk_style_context_remove_class(ctx, "notif-err");
|
||||
gtk_style_context_add_class(ctx, is_error ? "notif-err" : "notif-ok");
|
||||
gtk_revealer_set_reveal_child(GTK_REVEALER(notif_bar_), TRUE);
|
||||
|
||||
/* auto-hide after 4 seconds */
|
||||
g_timeout_add(4000, [](gpointer data) -> gboolean {
|
||||
gtk_revealer_set_reveal_child(GTK_REVEALER(data), FALSE);
|
||||
return G_SOURCE_REMOVE;
|
||||
}, notif_bar_);
|
||||
}
|
||||
|
||||
void SshClientWindow::update_server_combo() {
|
||||
@@ -141,6 +240,11 @@ void SshClientWindow::update_server_combo() {
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(server_combo_), 0);
|
||||
}
|
||||
|
||||
void SshClientWindow::update_server_list() {
|
||||
refresh_server_list_widget(server_listbox_, server_store_.servers());
|
||||
update_server_combo();
|
||||
}
|
||||
|
||||
void SshClientWindow::update_status(const std::string& msg) {
|
||||
if (!statusbar_) return;
|
||||
guint ctx_id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar_), "main");
|
||||
@@ -175,7 +279,6 @@ void SshClientWindow::close_tab_at(int idx) {
|
||||
GtkWidget* page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook_), idx);
|
||||
if (!page) return;
|
||||
|
||||
/* Find and disconnect the terminal first, before removing from notebook */
|
||||
SshTerminal* found = nullptr;
|
||||
for (auto it = terminals_.begin(); it != terminals_.end(); ++it) {
|
||||
if ((*it)->widget() == page) {
|
||||
@@ -190,7 +293,6 @@ void SshClientWindow::close_tab_at(int idx) {
|
||||
delete found;
|
||||
}
|
||||
|
||||
/* Now safe to remove page — no page-removed callback will cause issues */
|
||||
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook_), idx);
|
||||
}
|
||||
|
||||
@@ -202,6 +304,7 @@ void SshClientWindow::disconnect() {
|
||||
if (t->widget() == page) {
|
||||
t->disconnect();
|
||||
update_status("Disconnected");
|
||||
show_notification("Server disconnected");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -229,6 +332,7 @@ void SshClientWindow::connect_to_server(const std::string& host, int port,
|
||||
bool ok = term->connect(host, port, user, keyfile, password);
|
||||
if (!ok) {
|
||||
update_status("Failed to connect to " + host);
|
||||
show_notification("Failed to connect to " + host, true);
|
||||
for (auto it = terminals_.begin(); it != terminals_.end(); ++it) {
|
||||
if (*it == term) { terminals_.erase(it); break; }
|
||||
}
|
||||
@@ -236,6 +340,7 @@ void SshClientWindow::connect_to_server(const std::string& host, int port,
|
||||
gtk_notebook_remove_page(GTK_NOTEBOOK(notebook_), idx);
|
||||
} else {
|
||||
update_status("Connected to " + user + "@" + host);
|
||||
show_notification("Server connected: " + user + "@" + host + ":" + std::to_string(port));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,6 +372,28 @@ void SshClientWindow::on_quick_connect(GtkWidget*, gpointer d) {
|
||||
self->show_password_dialog(host, port, u, "", host);
|
||||
}
|
||||
|
||||
/* ─── server row activated ────────────────────────────────── */
|
||||
|
||||
void SshClientWindow::on_server_row_activated(GtkListBox*, GtkListBoxRow* row, gpointer d) {
|
||||
auto* self = static_cast<SshClientWindow*>(d);
|
||||
int idx = gtk_list_box_row_get_index(row);
|
||||
if (idx < 0 || idx >= (int)self->server_store_.servers().size()) return;
|
||||
const auto& s = self->server_store_.servers()[idx];
|
||||
|
||||
if (s.use_key && !s.keyfile.empty()) {
|
||||
self->connect_to_server(s.host, s.port, s.user, s.keyfile, "", s.name);
|
||||
} else {
|
||||
self->show_password_dialog(s.host, s.port, s.user, s.keyfile, s.name);
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── add server button ───────────────────────────────────── */
|
||||
|
||||
void SshClientWindow::on_add_server(GtkWidget*, gpointer d) {
|
||||
auto* self = static_cast<SshClientWindow*>(d);
|
||||
self->show_server_dialog(-1);
|
||||
}
|
||||
|
||||
/* ─── password dialog ─────────────────────────────────────── */
|
||||
|
||||
void SshClientWindow::show_password_dialog(const std::string& host, int port,
|
||||
@@ -407,7 +534,8 @@ void SshClientWindow::show_server_dialog(int edit_index) {
|
||||
if (!s.name.empty() && !s.host.empty() && !s.user.empty()) {
|
||||
if (editing) server_store_.update(edit_index, s);
|
||||
else server_store_.add(s);
|
||||
update_server_combo();
|
||||
update_server_list();
|
||||
show_notification(editing ? "Server updated: " + s.name : "Server saved: " + s.name);
|
||||
}
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
@@ -438,7 +566,7 @@ void SshClientWindow::show_key_dialog() {
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), listbox);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
|
||||
|
||||
refresh_key_list(listbox, key_store_.keys());
|
||||
refresh_key_list_widget(listbox, key_store_.keys());
|
||||
|
||||
GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
GtkWidget* gen_btn = gtk_button_new_with_label("Generate New Key");
|
||||
@@ -484,8 +612,9 @@ void SshClientWindow::show_key_dialog() {
|
||||
int bits = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(bs));
|
||||
if (name && *name) {
|
||||
c->self->key_store_.generate_keypair(name, bits);
|
||||
c->self->update_server_combo();
|
||||
refresh_key_list(c->listbox, c->self->key_store_.keys());
|
||||
c->self->update_server_list();
|
||||
refresh_key_list_widget(c->listbox, c->self->key_store_.keys());
|
||||
c->self->show_notification("Key generated: " + std::string(name));
|
||||
}
|
||||
}
|
||||
gtk_widget_destroy(dlg);
|
||||
@@ -529,7 +658,8 @@ void SshClientWindow::show_key_dialog() {
|
||||
const char* name = gtk_entry_get_text(GTK_ENTRY(ne));
|
||||
if (name && *name) {
|
||||
c->self->key_store_.import_key(name, path);
|
||||
refresh_key_list(c->listbox, c->self->key_store_.keys());
|
||||
refresh_key_list_widget(c->listbox, c->self->key_store_.keys());
|
||||
c->self->show_notification("Key imported: " + std::string(name));
|
||||
}
|
||||
}
|
||||
gtk_widget_destroy(dlg);
|
||||
@@ -545,8 +675,10 @@ void SshClientWindow::show_key_dialog() {
|
||||
if (!row) return;
|
||||
int idx = gtk_list_box_row_get_index(row);
|
||||
if (idx >= 0 && idx < (int)c->self->key_store_.keys().size()) {
|
||||
std::string name = c->self->key_store_.keys()[idx].name;
|
||||
c->self->key_store_.remove(idx);
|
||||
refresh_key_list(c->listbox, c->self->key_store_.keys());
|
||||
refresh_key_list_widget(c->listbox, c->self->key_store_.keys());
|
||||
c->self->show_notification("Key deleted: " + name);
|
||||
}
|
||||
}), ctx);
|
||||
|
||||
@@ -585,7 +717,7 @@ void SshClientWindow::on_manage_servers(GtkWidget*, gpointer d) {
|
||||
gtk_container_add(GTK_CONTAINER(scrolled), listbox);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), scrolled, TRUE, TRUE, 0);
|
||||
|
||||
refresh_server_list(listbox, self->server_store_.servers());
|
||||
refresh_server_list_widget(listbox, self->server_store_.servers());
|
||||
|
||||
GtkWidget* hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
GtkWidget* add_btn = gtk_button_new_with_label("Add");
|
||||
@@ -601,8 +733,8 @@ void SshClientWindow::on_manage_servers(GtkWidget*, gpointer d) {
|
||||
g_signal_connect(add_btn, "clicked", G_CALLBACK(+[](GtkWidget*, gpointer d) {
|
||||
auto* c = static_cast<SrvCtx*>(d);
|
||||
c->self->show_server_dialog(-1);
|
||||
c->self->update_server_combo();
|
||||
refresh_server_list(c->listbox, c->self->server_store_.servers());
|
||||
c->self->update_server_list();
|
||||
refresh_server_list_widget(c->listbox, c->self->server_store_.servers());
|
||||
}), ctx);
|
||||
|
||||
g_signal_connect(edit_btn, "clicked", G_CALLBACK(+[](GtkWidget*, gpointer d) {
|
||||
@@ -612,8 +744,8 @@ void SshClientWindow::on_manage_servers(GtkWidget*, gpointer d) {
|
||||
int idx = gtk_list_box_row_get_index(row);
|
||||
if (idx >= 0 && idx < (int)c->self->server_store_.servers().size()) {
|
||||
c->self->show_server_dialog(idx);
|
||||
c->self->update_server_combo();
|
||||
refresh_server_list(c->listbox, c->self->server_store_.servers());
|
||||
c->self->update_server_list();
|
||||
refresh_server_list_widget(c->listbox, c->self->server_store_.servers());
|
||||
}
|
||||
}), ctx);
|
||||
|
||||
@@ -623,9 +755,11 @@ void SshClientWindow::on_manage_servers(GtkWidget*, gpointer d) {
|
||||
if (!row) return;
|
||||
int idx = gtk_list_box_row_get_index(row);
|
||||
if (idx >= 0 && idx < (int)c->self->server_store_.servers().size()) {
|
||||
std::string name = c->self->server_store_.servers()[idx].name;
|
||||
c->self->server_store_.remove(idx);
|
||||
c->self->update_server_combo();
|
||||
refresh_server_list(c->listbox, c->self->server_store_.servers());
|
||||
c->self->update_server_list();
|
||||
refresh_server_list_widget(c->listbox, c->self->server_store_.servers());
|
||||
c->self->show_notification("Server removed: " + name);
|
||||
}
|
||||
}), ctx);
|
||||
|
||||
@@ -634,7 +768,7 @@ void SshClientWindow::on_manage_servers(GtkWidget*, gpointer d) {
|
||||
gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
delete ctx;
|
||||
gtk_widget_destroy(dialog);
|
||||
self->update_server_combo();
|
||||
self->update_server_list();
|
||||
}
|
||||
|
||||
/* ─── callbacks ───────────────────────────────────────────── */
|
||||
@@ -664,5 +798,6 @@ void SshClientWindow::on_manage_keys(GtkWidget*, gpointer d) {
|
||||
|
||||
void SshClientWindow::run() {
|
||||
gtk_widget_show_all(window_);
|
||||
gtk_revealer_set_reveal_child(GTK_REVEALER(notif_bar_), FALSE);
|
||||
gtk_main();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user