1 /*-
2 * Copyright (c) 2008 Jannis Pohlmann <jannis@xfce.org>
3 * Copyright (c) 2012 Guido Berhoerster <guido+xfce@berhoerster.name>
4 * Copyright (c) 2020 - 2021 Rozhuk Ivan <rozhuk.im@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22
23 #include <sys/param.h>
24 #include <sys/types.h>
25 #include <inttypes.h>
26
27 #include "gtk-mixer.h"
28
29
30 static void
gtk_mixer_container_destroy(GtkWidget * container __unused,gpointer user_data)31 gtk_mixer_container_destroy(GtkWidget *container __unused, gpointer user_data) {
32 GHashTable *widgets = user_data;
33
34 g_hash_table_remove_all(widgets);
35 g_hash_table_unref(widgets);
36 }
37
38 GtkWidget *
gtk_mixer_container_create(void)39 gtk_mixer_container_create(void) {
40 GtkWidget *container;
41 GHashTable *widgets;
42
43 container = gtk_notebook_new();
44 gtk_notebook_set_show_border(GTK_NOTEBOOK(container), TRUE);
45 widgets = g_hash_table_new_full(g_str_hash,
46 g_str_equal, g_free, NULL);
47 g_object_set_data(G_OBJECT(container),
48 "__gtk_mixer_container_widgets", widgets);
49 g_signal_connect(container, "destroy",
50 G_CALLBACK(gtk_mixer_container_destroy), widgets);
51
52 return (container);
53 }
54
55 static void
gtk_mixer_container_create_contents(GtkWidget * container,GHashTable * widgets,gmp_dev_p dev)56 gtk_mixer_container_create_contents(GtkWidget *container,
57 GHashTable *widgets, gmp_dev_p dev) {
58 gmp_dev_line_p line;
59 const gchar *titles[4] = { N_("_Playback"), N_("C_apture"),
60 N_("S_witches"), N_("_Options") };
61 GtkWidget *line_widget, *line_label_widget;
62 GtkWidget *labels[4], *scrollwins[4], *views[4];
63 GtkWidget *last_separator[4] = { NULL, NULL, NULL, NULL };
64 GtkWidget *vbox, *label1, *label2, *label3;
65 const char *line_label;
66 gint num_children[4] = { 0, 0, 0, 0 };
67 gboolean no_controls_visible = TRUE;
68
69 /* Create widgets for all four tabs. */
70 for (size_t i = 0; i < 4; i ++) {
71 labels[i] = gtk_label_new_with_mnemonic(_(titles[i]));
72 scrollwins[i] = gtk_scrolled_window_new(NULL, NULL);
73 gtk_scrolled_window_set_shadow_type(
74 GTK_SCROLLED_WINDOW(scrollwins[i]), GTK_SHADOW_IN);
75 gtk_container_set_border_width(GTK_CONTAINER(scrollwins[i]),
76 BORDER_WIDTH);
77 gtk_scrolled_window_set_policy(
78 GTK_SCROLLED_WINDOW(scrollwins[i]),
79 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
80
81 views[i] = gtk_grid_new();
82 g_object_set(G_OBJECT(views[i]),
83 "row-spacing", BORDER_WIDTH,
84 "column-spacing", (BORDER_WIDTH * 2),
85 "border-width", BORDER_WIDTH, NULL);
86 gtk_container_add(GTK_CONTAINER(scrollwins[i]), views[i]);
87 gtk_viewport_set_shadow_type(GTK_VIEWPORT(
88 gtk_bin_get_child(GTK_BIN(scrollwins[i]))),
89 GTK_SHADOW_NONE);
90 gtk_widget_show(views[i]);
91 gtk_widget_show(scrollwins[i]);
92 }
93
94 /* Create controls for all mixer lines. */
95 //preferences = gtk_mixer_preferences_get();
96 for (size_t i = 0; NULL != dev && i < dev->lines_count; i ++) {
97 line = &dev->lines[i];
98 line_label = line->display_name;
99
100 //if (!gtk_mixer_preferences_get_control_visible(
101 // preferences, line_label))
102 // continue;
103
104 size_t idx = ((0 == line->is_capture) ? 0 : 1);
105 /* Create a regular volume control for this line. */
106 line_label_widget = gtk_label_new(line_label);
107 gtk_grid_attach(GTK_GRID(views[idx]),
108 line_label_widget, num_children[idx], 0, 1, 1);
109 gtk_widget_show(line_label_widget);
110 line_widget = gtk_mixer_line_create(dev, line);
111 g_object_set(G_OBJECT(line_widget),
112 "valign", GTK_ALIGN_FILL,
113 "vexpand", TRUE, NULL);
114 gtk_grid_attach(GTK_GRID(views[idx]),
115 line_widget, num_children[idx], 1, 1, 1);
116 gtk_widget_show(line_widget);
117 num_children[idx]++;
118
119 /* Append a separator. The last one will be
120 * destroyed later. */
121 last_separator[idx] = gtk_separator_new(
122 GTK_ORIENTATION_VERTICAL);
123 gtk_grid_attach(GTK_GRID(views[idx]),
124 last_separator[idx], num_children[idx], 0, 1, 2);
125 gtk_widget_show(last_separator[idx]);
126 num_children[idx]++;
127
128 /* Add the line to the hash table. */
129 g_hash_table_insert(widgets,
130 g_strdup(line_label), line_widget);
131
132 #if 0
133 case XFCE_MIXER_TRACK_TYPE_SWITCH:
134 line_widget = gtk_mixer_switch_new(
135 container->card, line);
136 g_object_set(G_OBJECT(line_widget),
137 "halign", GTK_ALIGN_FILL,
138 "hexpand", TRUE, NULL);
139 gtk_grid_attach(GTK_GRID(views[2]),
140 line_widget, 0, num_children[2], 1, 1);
141 gtk_widget_show(line_widget);
142
143 num_children[2]++;
144
145 /* Add the line to the hash table. */
146 g_hash_table_insert(container->widgets,
147 g_strdup(line_label), line_widget);
148 break;
149
150 case XFCE_MIXER_TRACK_TYPE_OPTIONS:
151 snprintf(option_line_label, sizeof(option_line_label),
152 "%s:", line_label);
153 line_label_widget = gtk_label_new(
154 option_line_label);
155 g_object_set(G_OBJECT(line_label_widget),
156 "halign", GTK_ALIGN_FILL, NULL);
157 gtk_grid_attach(GTK_GRID(views[3]),
158 line_label_widget, 0, num_children[3], 1, 1);
159 gtk_widget_show(line_label_widget);
160
161 line_widget = gtk_mixer_option_new(
162 container->card, line);
163 g_object_set(G_OBJECT(line_widget),
164 "halign", GTK_ALIGN_FILL,
165 "hexpand", TRUE, NULL);
166 gtk_grid_attach(GTK_GRID(views[3]),
167 line_widget, 1, num_children[3], 1, 1);
168 gtk_widget_show(line_widget);
169
170 num_children[3]++;
171
172 /* Add the line to the hash table. */
173 g_hash_table_insert(container->widgets,
174 g_strdup(line_label), line_widget);
175 break;
176 #endif
177 }
178
179 /* Append tab or destroy all its widgets - depending on the
180 * contents of each tab. */
181 for (gint i = 0; i < 4; i ++) {
182 /* Destroy the last separator in the tab. */
183 if (last_separator[i] != NULL) {
184 gtk_widget_destroy(last_separator[i]);
185 }
186
187 gtk_notebook_append_page(GTK_NOTEBOOK(container),
188 scrollwins[i], labels[i]);
189
190 /* Hide tabs with no visible controls. */
191 if (num_children[i] > 0) {
192 no_controls_visible = FALSE;
193 } else {
194 gtk_widget_hide(gtk_notebook_get_nth_page(
195 GTK_NOTEBOOK(container), i));
196 }
197 }
198 /* Show informational message if no controls are visible. */
199 if (no_controls_visible) {
200 label1 = gtk_label_new(_("No controls visible"));
201 gtk_widget_show(label1);
202
203 vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
204 g_object_set(G_OBJECT(vbox),
205 "halign", GTK_ALIGN_CENTER,
206 "hexpand", TRUE,
207 "valign", GTK_ALIGN_CENTER,
208 "vexpand", TRUE,
209 "border-width", BORDER_WIDTH, NULL);
210 gtk_widget_show(vbox);
211
212 label2 = gtk_label_new(NULL);
213 gtk_label_set_markup(GTK_LABEL(label2),
214 _("<span weight=\"bold\" size=\"larger\">No controls visible</span>"));
215 g_object_set(G_OBJECT(label2),
216 "max-width-chars", 80,
217 "xalign", 0.0,
218 "wrap", TRUE, NULL);
219 gtk_box_pack_start(GTK_BOX(vbox), label2, FALSE, TRUE, 0);
220 gtk_widget_show(label2);
221
222 label3 = gtk_label_new(NULL);
223 gtk_label_set_markup(GTK_LABEL(label3),
224 _("In order to toggle the visibility of mixer controls, open the <b>\"Select Controls\"</b> dialog."));
225 g_object_set(G_OBJECT(label3),
226 "max-width-chars", 80,
227 "xalign", 0.0,
228 "wrap", TRUE, NULL);
229 gtk_box_pack_start(GTK_BOX(vbox), label3, FALSE, TRUE, 0);
230 gtk_widget_show(label3);
231
232 gtk_notebook_append_page(GTK_NOTEBOOK(container), vbox,
233 label1);
234 }
235 }
236
237 void
gtk_mixer_container_dev_set(GtkWidget * container,gmp_dev_p dev)238 gtk_mixer_container_dev_set(GtkWidget *container, gmp_dev_p dev) {
239 gint current_tab, i;
240 GHashTable *widgets = g_object_get_data(G_OBJECT(container),
241 "__gtk_mixer_container_widgets");
242
243 g_hash_table_remove_all(widgets);
244
245 /* Remember active tab */
246 current_tab = gtk_notebook_get_current_page(GTK_NOTEBOOK(container));
247
248 /* Destroy all tabs */
249 for (i = gtk_notebook_get_n_pages(GTK_NOTEBOOK(container)); i >= 0; i --) {
250 gtk_notebook_remove_page(GTK_NOTEBOOK(container), i);
251 }
252
253 /* Re-create contents */
254 gtk_mixer_container_create_contents(container, widgets, dev);
255
256 /* Restore previously active tab if possible */
257 if (current_tab > 0 && current_tab < 4) {
258 gtk_notebook_set_current_page(GTK_NOTEBOOK(container),
259 current_tab);
260 }
261 }
262
263 void
gtk_mixer_container_update(GtkWidget * container)264 gtk_mixer_container_update(GtkWidget *container) {
265 GtkWidget *line_widget;
266 GHashTable *widgets = g_object_get_data(G_OBJECT(container),
267 "__gtk_mixer_container_widgets");
268 GHashTableIter iter;
269
270 if (NULL == container || NULL == widgets)
271 return;
272
273 g_hash_table_iter_init(&iter, widgets);
274 while (g_hash_table_iter_next(&iter, NULL, (void**)&line_widget)) {
275 gtk_mixer_line_update(line_widget);
276 }
277 }
278