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.
86 lines
3.9 KiB
C
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;
|
|
}
|