1 /*-
2  * Copyright (c) 2008 Jannis Pohlmann <jannis@xfce.org>
3  * Copyright (c) 2020 - 2021 Rozhuk Ivan <rozhuk.im@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 
22 #include <sys/param.h>
23 #include <sys/types.h>
24 #include <inttypes.h>
25 
26 #include "gtk-mixer.h"
27 
28 #define GM_CMB_DEVS_COLUMN_NAME	0
29 #define GM_CMB_DEVS_COLUMN_CARD	1
30 
31 
32 static void
gtk_mixer_devs_combo_changed(GtkWidget * combo,gpointer user_data __unused)33 gtk_mixer_devs_combo_changed(GtkWidget *combo, gpointer user_data __unused) {
34 	GtkTreeIter iter;
35 	GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
36 	    "__gtk_mixer_devs_combo_list_store");
37 	gmp_dev_p dev_new = NULL;
38 	gmp_dev_p dev_old = g_object_get_data(G_OBJECT(combo),
39 	    "__gtk_mixer_devs_combo_current");
40 
41 	if (NULL == list_store)
42 		return;
43 	if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter)) {
44 		gtk_tree_model_get(GTK_TREE_MODEL(list_store), &iter,
45 		    GM_CMB_DEVS_COLUMN_CARD, &dev_new, -1);
46 	}
47 
48 	/* Init/uninit here, before other get notification. */
49 	gmp_dev_init(dev_new);
50 	g_object_set_data(G_OBJECT(combo),
51 	    "__gtk_mixer_devs_combo_current", dev_new);
52 	gmp_dev_uninit(dev_old);
53 }
54 
55 static void
gtk_mixer_devs_combo_destroy(GtkWidget * combo __unused,gpointer user_data)56 gtk_mixer_devs_combo_destroy(GtkWidget *combo __unused, gpointer user_data) {
57 	GtkListStore *list_store = user_data;
58 
59 	gtk_list_store_clear(list_store);
60 	g_object_unref(list_store);
61 }
62 
63 GtkWidget *
gtk_mixer_devs_combo_create(void)64 gtk_mixer_devs_combo_create(void) {
65 	GtkWidget *combo;
66 	GtkListStore *list_store;
67 	GtkCellRenderer *renderer;
68 
69 	combo = gtk_combo_box_new();
70 
71 	list_store = gtk_list_store_new(2, G_TYPE_STRING,
72 	    G_TYPE_POINTER);
73 	g_object_set_data(G_OBJECT(combo),
74 	    "__gtk_mixer_devs_combo_list_store", list_store);
75 	gtk_combo_box_set_model(GTK_COMBO_BOX(combo),
76 	    GTK_TREE_MODEL(list_store));
77 
78 	g_signal_connect(combo, "changed",
79 	    G_CALLBACK(gtk_mixer_devs_combo_changed), NULL);
80 	g_signal_connect(combo, "destroy",
81 	    G_CALLBACK(gtk_mixer_devs_combo_destroy), list_store);
82 
83 	renderer = gtk_cell_renderer_text_new();
84 	g_object_set(G_OBJECT(renderer), "ellipsize",
85 	    PANGO_ELLIPSIZE_END, NULL);
86 	gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo), renderer, TRUE);
87 	gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(combo), renderer,
88 	    "text", GM_CMB_DEVS_COLUMN_NAME);
89 
90 	return (combo);
91 }
92 
93 gmp_dev_p
gtk_mixer_devs_combo_cur_get(GtkWidget * combo)94 gtk_mixer_devs_combo_cur_get(GtkWidget *combo) {
95 
96 	if (NULL == combo)
97 		return (NULL);
98 	return (g_object_get_data(G_OBJECT(combo),
99 	    "__gtk_mixer_devs_combo_current"));
100 }
101 
102 void
gtk_mixer_devs_combo_cur_set(GtkWidget * combo,gmp_dev_p dev)103 gtk_mixer_devs_combo_cur_set(GtkWidget *combo,
104     gmp_dev_p dev) {
105 	gmp_dev_p device_cur = NULL;
106 	GtkTreeIter iter;
107 	gboolean valid_iter;
108 	GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
109 	    "__gtk_mixer_devs_combo_list_store");
110 
111 	if (NULL == dev || NULL == list_store) {
112 		gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0);
113 		return;
114 	}
115 	valid_iter = gtk_tree_model_get_iter_first(
116 	    GTK_TREE_MODEL(list_store), &iter);
117 	while (valid_iter) {
118 		gtk_tree_model_get(GTK_TREE_MODEL(list_store),
119 		    &iter, GM_CMB_DEVS_COLUMN_CARD, &device_cur, -1);
120 		if (device_cur == dev) {
121 			gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo),
122 			    &iter);
123 			break;
124 		}
125 		valid_iter = gtk_tree_model_iter_next(
126 		    GTK_TREE_MODEL(list_store), &iter);
127 	}
128 }
129 
130 static inline void
gtk_mixer_devs_combo_dev_descr(gmp_dev_p dev,char * buf,size_t buf_size)131 gtk_mixer_devs_combo_dev_descr(gmp_dev_p dev, char *buf, size_t buf_size) {
132 
133 	if (NULL == buf || 0 == buf_size)
134 		return;
135 	if (NULL == dev) {
136 		buf[0] = 0x00;
137 		return;
138 	}
139 	snprintf(buf, buf_size,
140 	    "%s: %s (%s)%s",
141 	    dev->plugin->descr->name,
142 	    dev->description,
143 	    dev->name,
144 	    ((gmp_dev_is_default(dev)) ? " [default]" : ""));
145 }
146 
147 void
gtk_mixer_devs_combo_dev_list_set(GtkWidget * combo,gmp_dev_list_p dev_list)148 gtk_mixer_devs_combo_dev_list_set(GtkWidget *combo, gmp_dev_list_p dev_list) {
149 	gmp_dev_p dev = NULL;
150 	GtkTreeIter iter;
151 	GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
152 	    "__gtk_mixer_devs_combo_list_store");
153 	char display_name[256];
154 
155 	if (NULL == list_store)
156 		return;
157 
158 	gtk_list_store_clear(list_store);
159 	if (NULL == dev_list)
160 		return;
161 	for (size_t i = 0; i < dev_list->count; i ++) {
162 		gtk_list_store_append(list_store, &iter);
163 		dev = &dev_list->devs[i];
164 		gtk_mixer_devs_combo_dev_descr(dev,
165 		    display_name, sizeof(display_name));
166 		gtk_list_store_set(list_store, &iter,
167 		    GM_CMB_DEVS_COLUMN_CARD, dev,
168 		    GM_CMB_DEVS_COLUMN_NAME, display_name, -1);
169 	}
170 }
171 void
gtk_mixer_devs_combo_update(GtkWidget * combo)172 gtk_mixer_devs_combo_update(GtkWidget *combo) {
173 	gmp_dev_p dev = NULL;
174 	GtkTreeIter iter;
175 	gboolean valid_iter;
176 	GtkListStore *list_store = g_object_get_data(G_OBJECT(combo),
177 	    "__gtk_mixer_devs_combo_list_store");
178 	char display_name[256];
179 
180 	if (NULL == list_store)
181 		return;
182 
183 	valid_iter = gtk_tree_model_get_iter_first(
184 	    GTK_TREE_MODEL(list_store), &iter);
185 	while (valid_iter) {
186 		gtk_tree_model_get(GTK_TREE_MODEL(list_store),
187 		    &iter, GM_CMB_DEVS_COLUMN_CARD, &dev, -1);
188 		gtk_mixer_devs_combo_dev_descr(dev,
189 		    display_name, sizeof(display_name));
190 		gtk_list_store_set(list_store, &iter,
191 		    GM_CMB_DEVS_COLUMN_NAME, display_name, -1);
192 		valid_iter = gtk_tree_model_iter_next(
193 		    GTK_TREE_MODEL(list_store), &iter);
194 	}
195 }
196