1 /* -*- linux-c -*-
2 Copyright (C) 2004 Tom Szilagyi
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: ports.c 1245 2012-02-04 10:33:30Z assworth $
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27 #include <glib-object.h>
28 #include <gdk/gdk.h>
29 #include <gtk/gtk.h>
30 #include <jack/jack.h>
31
32 #include "common.h"
33 #include "utils_gui.h"
34 #include "i18n.h"
35 #include "ports.h"
36
37
38 #define LIST_WIDTH 200
39 #define LIST_HEIGHT 100
40
41
42 extern GtkWidget * main_window;
43
44 /* JACK data */
45 extern jack_port_t * out_L_port;
46 extern jack_port_t * out_R_port;
47 extern jack_client_t * jack_client;
48
49 GtkWidget * ports_window = NULL;
50 GtkWidget * nb_outs;
51 GtkWidget * nb_out_labels[MAX_JACK_CLIENTS];
52
53 GtkWidget * vbox_dl; /* down-left */
54 GtkWidget * vbox_dr; /* down-right */
55
56 GtkWidget * tree_out_L;
57 GtkWidget * tree_out_R;
58 GtkListStore * store_out_L;
59 GtkListStore * store_out_R;
60 GtkTreeViewColumn * column_out_L;
61 GtkTreeViewColumn * column_out_R;
62
63 int n_clients;
64 GtkListStore * store_out_nb[MAX_JACK_CLIENTS];
65
66 gint timeout_tag;
67
68 int out_selector = 0;
69
70
71 void scan_connections(jack_port_t * port, GtkListStore * store);
72 void setup_notebook_out(void);
73
74
75
76 gint
ports_timeout_callback(gpointer data)77 ports_timeout_callback(gpointer data) {
78
79 switch(GPOINTER_TO_INT(data)) {
80 case 1:
81 gtk_list_store_clear(store_out_L);
82 scan_connections(out_L_port, store_out_L);
83 break;
84 case 2:
85 gtk_list_store_clear(store_out_R);
86 scan_connections(out_R_port, store_out_R);
87 break;
88 }
89 return 0;
90 }
91
92
93 int
port_window_close(GtkWidget * widget,gpointer * data)94 port_window_close(GtkWidget *widget, gpointer * data) {
95
96 ports_window = NULL;
97 return 0;
98 }
99
100
101 void
clicked_rescan(GtkWidget * widget,gpointer * data)102 clicked_rescan(GtkWidget * widget, gpointer * data) {
103
104 gtk_list_store_clear(store_out_L);
105 scan_connections(out_L_port, store_out_L);
106 gtk_list_store_clear(store_out_R);
107 scan_connections(out_R_port, store_out_R);
108
109 /* re-build notebook */
110 gtk_widget_destroy(nb_outs);
111 n_clients = 0;
112
113 nb_outs = gtk_notebook_new();
114 gtk_box_pack_start(GTK_BOX(vbox_dr), nb_outs, TRUE, TRUE, 2);
115 setup_notebook_out();
116 gtk_widget_show(nb_outs);
117 }
118
119
120 void
ports_clicked_close(GtkWidget * widget,gpointer * data)121 ports_clicked_close(GtkWidget * widget, gpointer * data) {
122
123 gtk_widget_destroy(ports_window);
124 ports_window = NULL;
125 }
126
127
128 void
set_active(GtkWidget * widget,int sel)129 set_active(GtkWidget * widget, int sel) {
130
131 GdkColor color_normal;
132 GdkColor color_active;
133 GdkColor color_prelight;
134
135 if (sel == 0) {
136 color_normal.red = 40000;
137 color_normal.green = 40000;
138 color_normal.blue = 40000;
139
140 color_active.red = 30000;
141 color_active.green = 30000;
142 color_active.blue = 30000;
143
144 color_prelight.red = 50000;
145 color_prelight.green = 50000;
146 color_prelight.blue = 50000;
147
148 } else {
149 color_normal.red = 40000;
150 color_normal.green = 40000;
151 color_normal.blue = 65535;
152
153 color_active.red = 30000;
154 color_active.green = 30000;
155 color_active.blue = 45000;
156
157 color_prelight.red = 50000;
158 color_prelight.green = 50000;
159 color_prelight.blue = 65535;
160 }
161 gtk_widget_modify_bg(widget, GTK_STATE_NORMAL, &color_normal);
162 gtk_widget_modify_bg(widget, GTK_STATE_ACTIVE, &color_active);
163 gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, &color_prelight);
164 }
165
166
167 void
clicked_out_L_header(GtkWidget * widget,gpointer * data)168 clicked_out_L_header(GtkWidget * widget, gpointer * data) {
169
170 out_selector = 0;
171 set_active(GTK_WIDGET(column_out_L->button), 1);
172 set_active(GTK_WIDGET(column_out_R->button), 0);
173 }
174
175
176 void
clicked_out_R_header(GtkWidget * widget,gpointer * data)177 clicked_out_R_header(GtkWidget * widget, gpointer * data) {
178
179 out_selector = 1;
180 set_active(GTK_WIDGET(column_out_L->button), 0);
181 set_active(GTK_WIDGET(column_out_R->button), 1);
182 }
183
184
185 void
tree_out_nb_selection_changed(GtkObject * tree,gpointer * data)186 tree_out_nb_selection_changed(GtkObject * tree, gpointer * data) {
187
188 GtkTreeIter iter;
189 GtkTreeModel * model;
190 GtkTreeSelection * selection;
191 gchar * str;
192 const gchar * label;
193 char fullname[MAXLEN];
194
195 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
196 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
197
198 gtk_tree_model_get(model, &iter, 0, &str, -1);
199 label = gtk_label_get_text(GTK_LABEL(nb_out_labels[GPOINTER_TO_INT(data)]));
200 sprintf(fullname, "%s:%s", label, str);
201 g_free(str);
202
203 if (out_selector == 0) {
204 if (jack_connect(jack_client, jack_port_name(out_L_port), fullname)) {
205 fprintf(stderr, "Cannot connect %s to out_L. "
206 "These ports are probably already connected.\n", fullname);
207 } else {
208 gtk_list_store_clear(store_out_L);
209 scan_connections(out_L_port, store_out_L);
210 out_selector = 1;
211 set_active(GTK_WIDGET(column_out_L->button), 0);
212 set_active(GTK_WIDGET(column_out_R->button), 1);
213 }
214 } else {
215 if (jack_connect(jack_client, jack_port_name(out_R_port), fullname)) {
216 fprintf(stderr, "Cannot connect %s to out_R. "
217 "These ports are probably already connected.\n", fullname);
218 } else {
219 gtk_list_store_clear(store_out_R);
220 scan_connections(out_R_port, store_out_R);
221 out_selector = 0;
222 set_active(GTK_WIDGET(column_out_L->button), 1);
223 set_active(GTK_WIDGET(column_out_R->button), 0);
224 }
225 }
226 }
227 }
228
229
230 void
tree_out_L_selection_changed(GtkTreeSelection * selection,gpointer * data)231 tree_out_L_selection_changed(GtkTreeSelection * selection, gpointer * data) {
232
233 GtkTreeIter iter;
234 GtkTreeModel * model;
235 gchar * str;
236 int res;
237
238 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
239
240 gtk_tree_model_get(model, &iter, 0, &str, -1);
241 if ((res = jack_disconnect(jack_client, jack_port_name(out_L_port), str)) != 0) {
242 fprintf(stderr, "ERROR: jack_disconnect() returned %d\n", res);
243 }
244 g_free(str);
245 timeout_tag = aqualung_timeout_add(100, ports_timeout_callback, GINT_TO_POINTER(1));
246 }
247 }
248
249
250 void
tree_out_R_selection_changed(GtkTreeSelection * selection,gpointer * data)251 tree_out_R_selection_changed(GtkTreeSelection *selection, gpointer * data) {
252
253 GtkTreeIter iter;
254 GtkTreeModel * model;
255 gchar * str;
256 int res;
257
258 if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
259
260 gtk_tree_model_get(model, &iter, 0, &str, -1);
261 if ((res = jack_disconnect(jack_client, jack_port_name(out_R_port), str)) != 0) {
262 fprintf(stderr, "ERROR: jack_disconnect() returned %d\n", res);
263 }
264 g_free(str);
265 timeout_tag = aqualung_timeout_add(100, ports_timeout_callback, (gpointer)2);
266 }
267 }
268
269
270 void
clear_outs(GtkWidget * widget,gpointer * data)271 clear_outs(GtkWidget * widget, gpointer * data) {
272
273 const char ** ports;
274 int i = 0;
275 int res;
276
277 ports = jack_port_get_connections(out_L_port);
278 if (ports) {
279 while (ports[i] != NULL) {
280 if ((res = jack_disconnect(jack_client, jack_port_name(out_L_port), ports[i])) != 0) {
281 fprintf(stderr, "ERROR: jack_disconnect() returned %d\n", res);
282 }
283 i++;
284 }
285 free(ports);
286 }
287 i = 0;
288 ports = jack_port_get_connections(out_R_port);
289 if (ports) {
290 while (ports[i] != NULL) {
291 if ((res = jack_disconnect(jack_client, jack_port_name(out_R_port), ports[i])) != 0) {
292 fprintf(stderr, "ERROR: jack_disconnect() returned %d\n", res);
293 }
294 i++;
295 }
296 free(ports);
297 }
298 gtk_list_store_clear(store_out_L);
299 gtk_list_store_clear(store_out_R);
300 }
301
302
303 void
scan_connections(jack_port_t * port,GtkListStore * store)304 scan_connections(jack_port_t * port, GtkListStore * store) {
305
306 GtkTreeIter iter;
307 const char ** ports;
308 int i = 0;
309
310 ports = jack_port_get_connections(port);
311
312 if (!ports)
313 return;
314
315 while (ports[i] != NULL) {
316 gtk_list_store_append(store, &iter);
317 gtk_list_store_set(store, &iter, 0, ports[i], -1);
318 i++;
319 }
320 free(ports);
321 }
322
323
324 GtkWidget *
setup_tree_out(void)325 setup_tree_out(void) {
326
327 GtkWidget * tree;
328 GtkCellRenderer * renderer;
329 GtkTreeViewColumn * column;
330 GtkTreeSelection * select;
331 GtkWidget * scrwin;
332
333 tree = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_out_nb[n_clients]));
334 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree), FALSE);
335 renderer = gtk_cell_renderer_text_new();
336 column = gtk_tree_view_column_new_with_attributes("inputs", renderer, "text", 0, NULL);
337 gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column);
338 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree), FALSE);
339
340 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
341 gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE);
342 g_signal_connect(G_OBJECT(tree), "cursor-changed", G_CALLBACK(tree_out_nb_selection_changed),
343 GINT_TO_POINTER(n_clients));
344
345 scrwin = gtk_scrolled_window_new(NULL, NULL);
346 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrwin),
347 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
348 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrwin), tree);
349 gtk_widget_set_size_request(GTK_WIDGET(scrwin), LIST_WIDTH, -1);
350
351 gtk_widget_show(tree);
352 gtk_widget_show(scrwin);
353
354 return scrwin;
355 }
356
357
358 void
setup_notebook_out(void)359 setup_notebook_out(void) {
360
361 const char ** ports_out;
362 int i, j, k;
363 char client_name[MAXLEN];
364 char client_name_prev[MAXLEN];
365 char port_name[MAXLEN];
366 GtkTreeIter iter;
367
368 ports_out = jack_get_ports(jack_client, NULL, NULL, JackPortIsInput);
369
370 for (j = 0; j < MAXLEN; j++) {
371 client_name[j] = '\0';
372 client_name_prev[j] = '\0';
373 }
374
375 i = 0;
376 n_clients = -1;
377 if (ports_out) {
378 while (ports_out[i] != NULL) {
379 /* get the client name */
380 j = 0;
381 while ((ports_out[i][j] != ':') && (ports_out[i][j] != '\0')) {
382 client_name[j] = ports_out[i][j];
383 j++;
384 }
385 client_name[j] = '\0';
386
387 /* create a new notebook page if needed */
388 if (strcmp(client_name, client_name_prev) != 0) {
389 n_clients++;
390 store_out_nb[n_clients] = gtk_list_store_new(1, G_TYPE_STRING);
391 nb_out_labels[n_clients] = gtk_label_new(client_name);
392 gtk_widget_show(nb_out_labels[n_clients]);
393 gtk_notebook_insert_page(GTK_NOTEBOOK(nb_outs), GTK_WIDGET(setup_tree_out()),
394 GTK_WIDGET(nb_out_labels[n_clients]), n_clients);
395 }
396 /* add the port to the list */
397 j = 0;
398 while ((ports_out[i][j] != ':') && (ports_out[i][j] != '\0'))
399 j++;
400 if (ports_out[i][j] == '\0')
401 fprintf(stderr, "ERROR: bad JACK port string: %s\n", ports_out[i]);
402 else {
403 k = 0;
404 j++;
405 while (ports_out[i][j] != '\0')
406 port_name[k++] = ports_out[i][j++];
407 port_name[k] = '\0';
408 gtk_list_store_append(store_out_nb[n_clients], &iter);
409 gtk_list_store_set(store_out_nb[n_clients], &iter, 0, port_name, -1);
410 }
411 strcpy(client_name_prev, client_name);
412 i++;
413 }
414 free(ports_out);
415 }
416 }
417
418
419 void
port_setup_dialog(void)420 port_setup_dialog(void) {
421
422 GtkWidget * vbox;
423 GtkWidget * table;
424 GtkWidget * button_rescan;
425 GtkWidget * button_close;
426 GtkWidget * button_clear_outs;
427 GtkWidget * frame_dl;
428 GtkWidget * frame_dr;
429
430 GtkCellRenderer * renderer_out_L;
431 GtkCellRenderer * renderer_out_R;
432 GtkTreeSelection * select_out_L;
433 GtkTreeSelection * select_out_R;
434
435 GtkWidget * viewp_out_L;
436 GtkWidget * viewp_out_R;
437
438 GtkWidget * hbox_L;
439 GtkWidget * hbox_R;
440
441 GtkWidget * label_L;
442 GtkWidget * label_R;
443
444 GdkColor color = { 0, 0, 0, 0 };
445
446
447 store_out_L = gtk_list_store_new(1, G_TYPE_STRING);
448 store_out_R = gtk_list_store_new(1, G_TYPE_STRING);
449
450 ports_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
451 gtk_window_set_title(GTK_WINDOW(ports_window), _("JACK Port Setup"));
452 gtk_window_set_position(GTK_WINDOW(ports_window), GTK_WIN_POS_CENTER);
453 gtk_window_set_modal(GTK_WINDOW(ports_window), TRUE);
454 gtk_window_set_transient_for(GTK_WINDOW(ports_window), GTK_WINDOW(main_window));
455 g_signal_connect(G_OBJECT(ports_window), "delete_event", G_CALLBACK(port_window_close), NULL);
456
457 vbox = gtk_vbox_new(FALSE, 0);
458 gtk_container_add(GTK_CONTAINER(ports_window), vbox);
459
460 table = gtk_table_new(2, 2, FALSE);
461 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 2);
462
463 button_rescan = gui_stock_label_button(_("Rescan"), GTK_STOCK_REFRESH);
464 gtk_table_attach(GTK_TABLE(table), button_rescan, 0, 1, 1, 2,
465 GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 5);
466 g_signal_connect(G_OBJECT(button_rescan), "clicked", G_CALLBACK(clicked_rescan), NULL);
467
468 button_close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
469 gtk_table_attach(GTK_TABLE(table), button_close, 1, 2, 1, 2,
470 GTK_FILL | GTK_EXPAND, GTK_FILL, 5, 5);
471 g_signal_connect(G_OBJECT(button_close), "clicked", G_CALLBACK(ports_clicked_close), NULL);
472
473 frame_dl = gtk_frame_new(_("Outputs"));
474 gtk_table_attach(GTK_TABLE(table), frame_dl, 0, 1, 0, 1,
475 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 5);
476
477 frame_dr = gtk_frame_new(_("Available connections"));
478 gtk_table_attach(GTK_TABLE(table), frame_dr, 1, 2, 0, 1,
479 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 5, 5);
480
481 vbox_dl = gtk_vbox_new(FALSE, 5);
482 gtk_container_set_border_width(GTK_CONTAINER(vbox_dl), 8);
483 gtk_container_add(GTK_CONTAINER(frame_dl), vbox_dl);
484
485 vbox_dr = gtk_vbox_new(FALSE, 5);
486 gtk_container_set_border_width(GTK_CONTAINER(vbox_dr), 8);
487 gtk_container_add(GTK_CONTAINER(frame_dr), vbox_dr);
488
489 button_clear_outs = gui_stock_label_button(_("Clear connections"), GTK_STOCK_CLEAR);
490 gtk_box_pack_start(GTK_BOX(vbox_dl), button_clear_outs, FALSE, TRUE, 2);
491 g_signal_connect(G_OBJECT(button_clear_outs), "clicked", G_CALLBACK(clear_outs), NULL);
492
493 nb_outs = gtk_notebook_new();
494 gtk_box_pack_start(GTK_BOX(vbox_dr), nb_outs, TRUE, TRUE, 2);
495
496 scan_connections(out_L_port, store_out_L);
497 scan_connections(out_R_port, store_out_R);
498
499 tree_out_L = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_out_L));
500 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree_out_L), FALSE);
501 tree_out_R = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store_out_R));
502 gtk_tree_view_set_enable_search(GTK_TREE_VIEW(tree_out_R), FALSE);
503 renderer_out_L = gtk_cell_renderer_text_new();
504 renderer_out_R = gtk_cell_renderer_text_new();
505 column_out_L = gtk_tree_view_column_new_with_attributes(NULL, renderer_out_L, "text", 0, NULL);
506 column_out_R = gtk_tree_view_column_new_with_attributes(NULL, renderer_out_R, "text", 0, NULL);
507
508 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_out_L), column_out_L);
509 gtk_tree_view_append_column(GTK_TREE_VIEW(tree_out_R), column_out_R);
510
511 g_signal_connect(G_OBJECT(column_out_L->button), "clicked", G_CALLBACK(clicked_out_L_header), NULL);
512 g_signal_connect(G_OBJECT(column_out_R->button), "clicked", G_CALLBACK(clicked_out_R_header), NULL);
513
514 gtk_widget_set_name(column_out_L->button, "nostyle");
515 gtk_widget_set_name(column_out_R->button, "nostyle");
516
517 select_out_L = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_out_L));
518 gtk_tree_selection_set_mode(select_out_L, GTK_SELECTION_SINGLE);
519 g_signal_connect(G_OBJECT(select_out_L), "changed", G_CALLBACK(tree_out_L_selection_changed), NULL);
520
521 select_out_R = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_out_R));
522 gtk_tree_selection_set_mode(select_out_R, GTK_SELECTION_SINGLE);
523 g_signal_connect(G_OBJECT(select_out_R), "changed", G_CALLBACK(tree_out_R_selection_changed), NULL);
524
525 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tree_out_L), TRUE);
526 gtk_tree_view_set_headers_clickable(GTK_TREE_VIEW(tree_out_R), TRUE);
527
528 viewp_out_L = gtk_viewport_new(NULL, NULL);
529 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewp_out_L), GTK_SHADOW_IN);
530 gtk_container_add(GTK_CONTAINER(viewp_out_L), tree_out_L);
531 gtk_widget_set_size_request(GTK_WIDGET(viewp_out_L), LIST_WIDTH, LIST_HEIGHT);
532
533 viewp_out_R = gtk_viewport_new(NULL, NULL);
534 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewp_out_R), GTK_SHADOW_IN);
535 gtk_container_add(GTK_CONTAINER(viewp_out_R), tree_out_R);
536 gtk_widget_set_size_request(GTK_WIDGET(viewp_out_R), LIST_WIDTH, LIST_HEIGHT);
537
538 gtk_box_pack_start(GTK_BOX(vbox_dl), viewp_out_L, TRUE, TRUE, 2);
539 gtk_box_pack_start(GTK_BOX(vbox_dl), viewp_out_R, TRUE, TRUE, 2);
540
541 setup_notebook_out();
542
543 set_active(GTK_WIDGET(column_out_L->button), TRUE);
544 set_active(GTK_WIDGET(column_out_R->button), FALSE);
545
546 gtk_widget_show_all(ports_window);
547
548 gtk_widget_destroy(gtk_bin_get_child(GTK_BIN(column_out_L->button)));
549 gtk_widget_destroy(gtk_bin_get_child(GTK_BIN(column_out_R->button)));
550
551 hbox_L = gtk_hbox_new(FALSE, 0);
552 hbox_R = gtk_hbox_new(FALSE, 0);
553
554 label_L = gtk_label_new(_(" out L"));
555 label_R = gtk_label_new(_(" out R"));
556
557 gtk_container_add(GTK_CONTAINER(column_out_L->button), hbox_L);
558 gtk_container_add(GTK_CONTAINER(column_out_R->button), hbox_R);
559
560 gtk_box_pack_start(GTK_BOX(hbox_L), label_L, FALSE, FALSE, 0);
561 gtk_box_pack_start(GTK_BOX(hbox_R), label_R, FALSE, FALSE, 0);
562
563 gtk_widget_modify_fg(label_L, GTK_STATE_NORMAL, &color);
564 gtk_widget_modify_fg(label_L, GTK_STATE_PRELIGHT, &color);
565 gtk_widget_modify_fg(label_L, GTK_STATE_ACTIVE, &color);
566
567 gtk_widget_modify_fg(label_R, GTK_STATE_NORMAL, &color);
568 gtk_widget_modify_fg(label_R, GTK_STATE_PRELIGHT, &color);
569 gtk_widget_modify_fg(label_R, GTK_STATE_ACTIVE, &color);
570
571 gtk_widget_show_all(hbox_L);
572 gtk_widget_show_all(hbox_R);
573 }
574
575
576 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
577
578