Files
hjozwiak 75f34ea767 Add global Wine preferences tab
Phase 3 of the Wine/Proton stage (decisions 6, 9, 13, 19 in docs/testing/wine-proton.md): a global-only Wine tab modeled on the Pronunciation page, with the controller-only checkbox and a typed editable program list. Wine values flow through the preferences protocol so a global Apply reaches the live Wine settings from Phase 2 with no reader restart. Entries are validated as edited and named in-tab, blocking Apply until fixed; case-insensitive duplicates collapse. Per-application preferences expose no Wine editing and an app-scoped Apply cannot change the governing list.
2026-11-02 02:49:33 -05:00

86 lines
3.9 KiB
C

// Copyright (c) 2026 Storm Dragon
// Authors: Storm Dragon, Angus Kola
// SPDX-License-Identifier: GPL-3.0-or-later
#include "native_internal.h"
enum { PROGRAM };
static GtkListStore *wine_programs;
static int wine_changed;
static void wine_edited(GtkCellRendererText *renderer, gchar *path, gchar *text, gpointer data) {
(void)renderer; (void)data;
GtkTreeIter iter;
if (gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(wine_programs), &iter, path)) {
gtk_list_store_set(wine_programs, &iter, PROGRAM, text, -1);
wine_changed = 1;
}
}
static void wine_add(GtkButton *button, gpointer data) {
(void)button; (void)data;
GtkTreeIter iter;
gtk_list_store_append(wine_programs, &iter);
gtk_list_store_set(wine_programs, &iter, PROGRAM, "", -1);
wine_changed = 1;
GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(wine_programs), &iter);
GtkTreeView *view = GTK_TREE_VIEW(prefs_widget("wineTreeView"));
gtk_widget_grab_focus(GTK_WIDGET(view));
gtk_tree_view_set_cursor(view, path, gtk_tree_view_get_column(view, PROGRAM), TRUE);
gtk_tree_path_free(path);
}
static void wine_delete(GtkButton *button, gpointer data) {
(void)button; (void)data;
GtkTreeIter iter;
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(prefs_widget("wineTreeView")));
if (gtk_tree_selection_get_selected(selection, NULL, &iter)) {
gtk_list_store_remove(wine_programs, &iter);
wine_changed = 1;
}
gtk_widget_grab_focus(prefs_widget("wineTreeView"));
}
static gboolean wine_key(GtkWidget *widget, GdkEventKey *event, gpointer data) {
(void)data;
if (event->keyval != GDK_KEY_Return && event->keyval != GDK_KEY_KP_Enter && event->keyval != GDK_KEY_F2) return FALSE;
GtkTreePath *path = NULL;
GtkTreeViewColumn *column = NULL;
gtk_tree_view_get_cursor(GTK_TREE_VIEW(widget), &path, &column);
if (!path) return FALSE;
gtk_tree_view_set_cursor(GTK_TREE_VIEW(widget), path, column ? column : gtk_tree_view_get_column(GTK_TREE_VIEW(widget), 0), TRUE);
gtk_tree_path_free(path);
return TRUE;
}
void prefs_init_wine(void) {
GtkTreeView *view = GTK_TREE_VIEW(prefs_widget("wineTreeView"));
wine_programs = gtk_list_store_new(1, G_TYPE_STRING);
gtk_tree_view_set_model(view, GTK_TREE_MODEL(wine_programs));
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
g_object_set(renderer, "editable", TRUE, NULL);
g_signal_connect(renderer, "edited", G_CALLBACK(wine_edited), NULL);
gtk_tree_view_append_column(view, gtk_tree_view_column_new_with_attributes("Program", renderer, "text", PROGRAM, NULL));
atk_object_set_name(gtk_widget_get_accessible(GTK_WIDGET(view)), "Controller-only programs");
atk_object_set_description(gtk_widget_get_accessible(GTK_WIDGET(view)), "Select a cell and press Enter to edit it. Tab moves to the next control.");
g_signal_connect(view, "key-press-event", G_CALLBACK(wine_key), NULL);
g_signal_connect(prefs_widget("wineAddButton"), "clicked", G_CALLBACK(wine_add), NULL);
g_signal_connect(prefs_widget("wineDeleteButton"), "clicked", G_CALLBACK(wine_delete), NULL);
g_object_unref(wine_programs);
}
int prefs_wine_changed(void) { int result = wine_changed; wine_changed = 0; return result; }
void prefs_wine_clear(void) { gtk_list_store_clear(wine_programs); }
void prefs_wine_append(const char *program) {
GtkTreeIter iter;
gtk_list_store_append(wine_programs, &iter);
gtk_list_store_set(wine_programs, &iter, PROGRAM, program, -1);
}
int prefs_wine_count(void) { return gtk_tree_model_iter_n_children(GTK_TREE_MODEL(wine_programs), NULL); }
char *prefs_wine_value(int row) {
GtkTreeIter iter;
if (!gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(wine_programs), &iter, NULL, row)) return NULL;
char *value = NULL;
gtk_tree_model_get(GTK_TREE_MODEL(wine_programs), &iter, PROGRAM, &value, -1);
return value;
}