164 lines
8.4 KiB
C
164 lines
8.4 KiB
C
// Copyright (c) 2026 Storm Dragon
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
#include "native_internal.h"
|
|
|
|
static GtkListStore *tentacleStore;
|
|
static gboolean updating;
|
|
|
|
static void name_toggle_cells(void) {
|
|
AtkObject *accessible = gtk_widget_get_accessible(prefs_widget("tentaclesTree"));
|
|
if (!ATK_IS_TABLE(accessible)) return;
|
|
int rows = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(tentacleStore), NULL);
|
|
for (int row = 0; row < rows; row++) {
|
|
AtkObject *cell = atk_table_ref_at(ATK_TABLE(accessible), row, 0);
|
|
if (!cell) continue;
|
|
GtkTreeIter iter;
|
|
gboolean enabled = FALSE;
|
|
gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(tentacleStore), &iter, NULL, row);
|
|
gtk_tree_model_get(GTK_TREE_MODEL(tentacleStore), &iter, 0, &enabled, -1);
|
|
atk_object_set_name(cell, enabled ? "checked" : "unchecked");
|
|
g_object_unref(cell);
|
|
}
|
|
}
|
|
static void tentacle_selected(GtkTreeSelection *selection, gpointer data) {
|
|
(void)selection; (void)data;
|
|
if (!updating) prefs_set_action(16);
|
|
}
|
|
static void tentacle_clicked(GtkButton *button, gpointer data) {
|
|
(void)button;
|
|
prefs_set_action(GPOINTER_TO_INT(data));
|
|
}
|
|
static void tentacle_toggled(GtkCellRendererToggle *renderer, gchar *pathString, gpointer data) {
|
|
(void)renderer; (void)data;
|
|
if (updating) return;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string(pathString);
|
|
gtk_tree_view_set_cursor(GTK_TREE_VIEW(prefs_widget("tentaclesTree")), path, NULL, FALSE);
|
|
gtk_tree_path_free(path);
|
|
// The accepted backend snapshot owns the check state; never check
|
|
// optimistically before persistence or after an operation has failed.
|
|
prefs_set_action(11);
|
|
}
|
|
static gboolean tentacle_key(GtkWidget *widget, GdkEventKey *event, gpointer data) {
|
|
(void)widget; (void)data;
|
|
if (event->keyval != GDK_KEY_space && event->keyval != GDK_KEY_KP_Space) return FALSE;
|
|
prefs_set_action(11);
|
|
return TRUE;
|
|
}
|
|
static void repository_switched(GtkNotebook *notebook, GtkWidget *page, guint index, gpointer data) {
|
|
(void)notebook; (void)index; (void)data;
|
|
GtkWidget *scroll = prefs_widget("tentacleTableScroll");
|
|
GtkWidget *parent = gtk_widget_get_parent(scroll);
|
|
if (parent != page) {
|
|
g_object_ref(scroll);
|
|
gtk_container_remove(GTK_CONTAINER(parent), scroll);
|
|
gtk_container_add(GTK_CONTAINER(page), scroll);
|
|
g_object_unref(scroll);
|
|
}
|
|
if (!updating) prefs_set_action(17);
|
|
}
|
|
void prefs_init_tentacles(void) {
|
|
updating = FALSE;
|
|
tentacleStore = gtk_list_store_new(7, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
|
|
GtkTreeView *tree = GTK_TREE_VIEW(prefs_widget("tentaclesTree"));
|
|
gtk_tree_view_set_model(tree, GTK_TREE_MODEL(tentacleStore));
|
|
GtkCellRenderer *toggle = gtk_cell_renderer_toggle_new();
|
|
g_signal_connect(toggle, "toggled", G_CALLBACK(tentacle_toggled), NULL);
|
|
gtk_tree_view_append_column(tree, gtk_tree_view_column_new_with_attributes("Enabled", toggle, "active", 0, NULL));
|
|
const char *titles[] = {"Name", "Status", "Version", "Repository", "Details", "Shortcuts"};
|
|
for (unsigned i = 0; i < G_N_ELEMENTS(titles); i++) {
|
|
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
|
|
gtk_tree_view_append_column(tree, gtk_tree_view_column_new_with_attributes(titles[i], renderer, "text", i + 1, NULL));
|
|
}
|
|
gtk_tree_selection_set_mode(gtk_tree_view_get_selection(tree), GTK_SELECTION_SINGLE);
|
|
g_signal_connect(gtk_tree_view_get_selection(tree), "changed", G_CALLBACK(tentacle_selected), NULL);
|
|
g_signal_connect(tree, "key-press-event", G_CALLBACK(tentacle_key), NULL);
|
|
g_signal_connect(prefs_widget("tentacleRepositories"), "switch-page", G_CALLBACK(repository_switched), NULL);
|
|
const struct { const char *id; int action; } buttons[] = {
|
|
{"tentacleNew", 9}, {"tentacleRetry", 13}, {"tentacleRemove", 14},
|
|
{"tentacleRefresh", 15}, {"tentacleRepositoryRemove", 12}, {"tentacleRepositoryRefresh", 18},
|
|
{"tentacleInstall", 19}, {"tentacleSettings", 20},
|
|
};
|
|
for (unsigned i = 0; i < G_N_ELEMENTS(buttons); i++)
|
|
g_signal_connect(prefs_widget(buttons[i].id), "clicked", G_CALLBACK(tentacle_clicked), GINT_TO_POINTER(buttons[i].action));
|
|
atk_object_set_name(gtk_widget_get_accessible(GTK_WIDGET(tree)), "Tentacles");
|
|
atk_object_set_name(gtk_widget_get_accessible(prefs_widget("tentacleRepositoryURL")), "Repository URL");
|
|
atk_object_set_name(gtk_widget_get_accessible(prefs_widget("tentacleRepositories")), "Tentacle repositories");
|
|
g_object_unref(tentacleStore); // Owned by the tree.
|
|
}
|
|
void prefs_tentacles_clear(void) {
|
|
updating = TRUE;
|
|
gtk_list_store_clear(tentacleStore);
|
|
}
|
|
void prefs_tentacle_append(int enabled, const char *name, const char *state, const char *version, const char *repository, const char *message, const char *shortcuts) {
|
|
GtkTreeIter iter;
|
|
gtk_list_store_append(tentacleStore, &iter);
|
|
gtk_list_store_set(tentacleStore, &iter, 0, enabled != 0, 1, name, 2, state, 3, version, 4, repository, 5, message, 6, shortcuts, -1);
|
|
}
|
|
int prefs_tentacle_selected(void) {
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreeView *tree = GTK_TREE_VIEW(prefs_widget("tentaclesTree"));
|
|
if (!gtk_tree_selection_get_selected(gtk_tree_view_get_selection(tree), &model, &iter)) return -1;
|
|
GtkTreePath *path = gtk_tree_model_get_path(model, &iter);
|
|
int row = gtk_tree_path_get_indices(path)[0];
|
|
gtk_tree_path_free(path);
|
|
return row;
|
|
}
|
|
void prefs_tentacle_select(int row) {
|
|
updating = TRUE;
|
|
GtkTreeView *tree = GTK_TREE_VIEW(prefs_widget("tentaclesTree"));
|
|
gtk_tree_selection_unselect_all(gtk_tree_view_get_selection(tree));
|
|
if (row >= 0) {
|
|
GtkTreePath *path = gtk_tree_path_new_from_indices(row, -1);
|
|
if (gtk_widget_has_focus(GTK_WIDGET(tree))) gtk_tree_view_set_cursor(tree, path, NULL, FALSE);
|
|
else gtk_tree_selection_select_path(gtk_tree_view_get_selection(tree), path);
|
|
gtk_tree_path_free(path);
|
|
}
|
|
name_toggle_cells();
|
|
updating = FALSE;
|
|
}
|
|
void prefs_tentacle_controls(int available, int installed, int enabled, int repository) {
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleNew"), available);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleRepositoryURL"), available);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleRetry"), available && installed && enabled);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleSettings"), available && installed);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleRemove"), available && installed);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleInstall"), available && !installed && prefs_tentacle_selected() >= 0);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleRepositoryRefresh"), available && repository);
|
|
gtk_widget_set_sensitive(prefs_widget("tentacleRepositoryRemove"), available && repository);
|
|
}
|
|
int prefs_tentacle_confirm(const char *message, const char *label) {
|
|
GtkWidget *dialog = gtk_message_dialog_new(GTK_WINDOW(prefs_widget("window")),
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
|
|
GTK_BUTTONS_NONE, "%s", message);
|
|
gtk_window_set_title(GTK_WINDOW(dialog), "Install tentacle");
|
|
gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", GTK_RESPONSE_CANCEL);
|
|
gtk_dialog_add_button(GTK_DIALOG(dialog), label, GTK_RESPONSE_ACCEPT);
|
|
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_CANCEL);
|
|
int response = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_destroy(dialog);
|
|
return response == GTK_RESPONSE_ACCEPT;
|
|
}
|
|
void prefs_tentacle_repositories_clear(void) {
|
|
updating = TRUE;
|
|
GtkNotebook *notebook = GTK_NOTEBOOK(prefs_widget("tentacleRepositories"));
|
|
gtk_notebook_set_current_page(notebook, 0);
|
|
while (gtk_notebook_get_n_pages(notebook) > 1) gtk_notebook_remove_page(notebook, -1);
|
|
updating = FALSE;
|
|
}
|
|
void prefs_tentacle_repository_append(const char *label) {
|
|
updating = TRUE;
|
|
GtkWidget *page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_notebook_append_page(GTK_NOTEBOOK(prefs_widget("tentacleRepositories")), page, gtk_label_new(label));
|
|
gtk_widget_show_all(page);
|
|
updating = FALSE;
|
|
}
|
|
int prefs_tentacle_repository_selected(void) {
|
|
return gtk_notebook_get_current_page(GTK_NOTEBOOK(prefs_widget("tentacleRepositories")));
|
|
}
|
|
void prefs_tentacle_repository_select(int page) {
|
|
updating = TRUE;
|
|
gtk_notebook_set_current_page(GTK_NOTEBOOK(prefs_widget("tentacleRepositories")), page);
|
|
updating = FALSE;
|
|
}
|