// SPDX-FileCopyrightText: 2022-2024 Geoffrey D. Bennett // SPDX-License-Identifier: GPL-3.0-or-later #include "widget-boolean.h" struct boolean { struct alsa_elem *elem; int backwards; GtkWidget *button; guint source; const char *text[2]; }; static void button_clicked(GtkWidget *widget, struct boolean *data) { int value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); alsa_set_elem_value(data->elem, value ^ data->backwards); } static void toggle_button_set_text(GtkWidget *button, const char *text) { if (!text) return; if (*text == '*') { GtkWidget *icon = gtk_image_new_from_icon_name(text + 1); gtk_button_set_child(GTK_BUTTON(button), icon); } else { gtk_button_set_label(GTK_BUTTON(button), text); } } static void toggle_button_updated( struct alsa_elem *elem, void *private ) { struct boolean *data = private; int is_writable = alsa_get_elem_writable(elem); gtk_widget_set_sensitive(data->button, is_writable); int value = !!alsa_get_elem_value(elem) ^ data->backwards; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(data->button), value); toggle_button_set_text(data->button, data->text[value]); } static gboolean update_toggle_button(struct boolean *data) { toggle_button_updated(data->elem, data); return G_SOURCE_CONTINUE; } static void on_destroy(struct boolean *data) { if (data->source) g_source_remove(data->source); g_free(data); } GtkWidget *make_boolean_alsa_elem( struct alsa_elem *elem, const char *disabled_text, const char *enabled_text ) { struct boolean *data = g_malloc0(sizeof(struct boolean)); data->elem = elem; data->button = gtk_toggle_button_new(); g_signal_connect( data->button, "clicked", G_CALLBACK(button_clicked), data ); alsa_elem_add_callback(elem, toggle_button_updated, data); data->text[0] = disabled_text; data->text[1] = enabled_text; // find the maximum width and height of both possible labels int max_width = 0, max_height = 0; for (int i = 0; i < 2; i++) { toggle_button_set_text(data->button, data->text[i]); GtkRequisition *size = gtk_requisition_new(); gtk_widget_get_preferred_size(data->button, size, NULL); if (size->width > max_width) max_width = size->width; if (size->height > max_height) max_height = size->height; } // set the widget minimum size to the maximum label size so that the // widget doesn't change size when the label changes gtk_widget_set_size_request(data->button, max_width, max_height); toggle_button_updated(elem, data); // periodically update volatile controls if (alsa_get_elem_volatile(elem)) data->source = g_timeout_add_seconds(1, (GSourceFunc)update_toggle_button, data); g_object_weak_ref(G_OBJECT(data->button), (GWeakNotify)on_destroy, data); return data->button; }