37 static PortAttr gx_head_ports[] = {
39 { 0,
false,
"in_0",
true, JACK_DEFAULT_AUDIO_TYPE },
40 { 1,
false,
"out_0",
false, JACK_DEFAULT_AUDIO_TYPE },
41 { 1,
false,
"out_1",
false, JACK_DEFAULT_AUDIO_TYPE },
42 { 0,
false,
"midi_in_1",
true, JACK_DEFAULT_MIDI_TYPE },
43 { 0,
false,
"midi_out_1",
false, JACK_DEFAULT_MIDI_TYPE },
44 { 1,
true,
"in_0",
true, JACK_DEFAULT_AUDIO_TYPE },
45 { 0,
true,
"out_0",
false, JACK_DEFAULT_AUDIO_TYPE },
48 #define ALSA_PCM "alsa_pcm" // special alsa sequencer gxjack.client
49 #define ALSA_PCM_LEN_1 9
57 struct ClientPortList {
60 list<const char*>
ports;
62 inline void add(
const char *p) {
ports.push_back(p); }
69 const char *q = strchr(p,
':');
73 q = strchr(p+
len,
'/');
85 struct ClientList: list<ClientPortList*> {
86 static bool str_compare(
const char *a,
const char *b);
93 return strcmp(b, a) > 0;
98 for (
int i = 0; ports[i]; ++i) {
99 l.push_back(ports[i]);
105 ClientPortList *cp =
new ClientPortList(*l.begin());
106 for (list<const char*>::iterator j = l.begin(); j != l.end(); ++j) {
107 if (!cp->sameclient(*j)) {
109 cp =
new ClientPortList(*j);
117 for (list<ClientPortList*>::iterator i = begin(); i !=
end(); ++i) {
123 for (list<ClientPortList*>::iterator i = begin(); i !=
end();) {
124 if ((*i)->sameclient(excl.c_str())) {
125 list<ClientPortList*>::iterator n = i++;
144 static string client_from_port(
const string& port) {
145 size_t pos = port.find_first_of(
':');
146 if (pos == string::npos) {
149 string s = port.substr(0, pos);
154 if (p2 == string::npos) {
157 return port.substr(0, p2);
160 static bool compare_client(
const string& name,
const string& p) {
161 if (name.compare(0, name.size(), p, 0, name.size()) == 0) {
162 if (p[name.size()] ==
':' || p.size() == name.size()) {
167 if (name.compare(0, name.size(), p,
ALSA_PCM_LEN_1, name.size()) == 0) {
176 static bool compare_port(
const string& name,
const char *p) {
177 return name.compare(p) == 0;
180 bool PortMapWindow::walk_remove(Glib::RefPtr<Gtk::TreeStore> ts,
bool (*compare)
181 (
const string&,
const char*),
string data) {
182 bool changed =
false;
183 Gtk::TreeIter i(ts->children().begin());
185 if ((*i)[columns.is_port]) {
186 if (data == (*i)[columns.port]) {
192 Gtk::TreeIter j(i->children().begin());
194 if (data == (*j)[columns.port]) {
207 void PortMapWindow::walk_insert(Glib::RefPtr<Gtk::TreeStore> ts,
string name) {
209 for (Gtk::TreeIter i(ts->children().begin()); i; ++i) {
210 Glib::ustring p = (*i)[columns.port];
214 if (!(*i)[columns.is_port] && compare_client(client_from_port(name), p)) {
216 for (Gtk::TreeIter j(i->children().begin()); j; ++j) {
218 if (name == (*j)[columns.port]) {
222 Gtk::TreeRow row = *ts->append(i->children());
223 row[columns.port] = name;
224 row[columns.connected] =
false;
225 row[columns.is_port] =
true;
229 Gtk::TreeRow row = *ts->append();
230 row[columns.port] = name;
231 row[columns.connected] =
false;
232 row[columns.is_port] =
true;
235 void PortMapWindow::port_changed(
string name,
const char *tp,
int flags,
bool reg) {
237 for (
int i = 0; i < number_of_ports; ++i) {
238 PortSection& p = portsection[i];
239 if (walk_remove(p.treestore, compare_port, name)) {
244 for (list<string>::iterator j = excluded_clients.begin();
245 j != excluded_clients.end(); ++j) {
246 if (name.compare(0, j->size(), *j) == 0) {
250 for (
int i = 0; i < number_of_ports; ++i) {
251 PortSection *p = &portsection[i];
252 if (strcmp(p->port_attr->port_type, tp) != 0) {
255 if (p->port_attr->is_input) {
256 if (!(flags & JackPortIsOutput)) {
260 if (!(flags & JackPortIsInput)) {
264 walk_insert(p->treestore, name);
274 list<string> PortMapWindow::walk(Glib::RefPtr<Gtk::TreeStore> ts,
string *port,
int connect) {
276 for (Gtk::TreeIter i(ts->children().begin()); i; ++i) {
277 Glib::ustring p = (*i)[columns.port];
278 bool is_connected = (*i)[columns.connected];
279 if ((*i)[columns.is_port]) {
280 if (port && port->compare(p) == 0) {
281 is_connected = connect;
282 (*i)[columns.connected] = connect;
288 for (Gtk::TreeIter j(i->children().begin()); j; ++j) {
289 Glib::ustring p = (*j)[columns.port];
290 bool is_connected = (*j)[columns.connected];
291 if (port && port->compare(p) == 0) {
292 is_connected = connect;
293 (*j)[columns.connected] = connect;
304 void PortMapWindow::update_summary(PortSection& p,
string *port,
bool conn) {
305 list<string> l = walk(p.treestore, port, conn);
310 list<string>::iterator i = l.begin();
314 for (; i != l.end(); ++i) {
317 p.label->set_text(q);
318 Glib::signal_idle().connect_once(
320 sigc::mem_fun(*
this, &PortMapWindow::redraw_expander), p.expander));
324 for (
int i = 0; i < number_of_ports; ++i) {
330 if (s.compare(port1) == 0) {
331 update_summary(p, &port2, conn);
332 }
else if (s.compare(port2) == 0) {
333 update_summary(p, &port1, conn);
343 void PortMapWindow::on_check_resize() {
345 if (monitored_expander_child &&
346 !monitored_expander_child->get_child_visible()) {
347 monitored_expander_child = 0;
348 int x, y, width, height, depth;
349 window->get_window()->get_geometry(x, y, width, height, depth);
350 window->resize(width, 1);
354 void PortMapWindow::on_expander(Gtk::Expander& expander) {
355 gboolean expanded = expander.get_expanded();
358 for (
int i = 0; i < number_of_ports; ++i) {
359 Gtk::Expander *w = portsection[i].
expander;
360 if (&expander != w) {
367 w->set_expanded(
false);
378 expander.set_expanded(expanded);
386 monitored_expander_child = expander.get_child();
390 void PortMapWindow::redraw_expander(Gtk::Expander* ex) {
394 void PortMapWindow::on_cell_toggle(Glib::ustring path, PortSection& p) {
395 Gtk::TreeIter iter(p.treestore->get_iter(path));
396 Glib::ustring q1 = (*iter)[columns.port];
397 bool v = (*iter)[columns.connected];
400 if (p.port_attr->client_num == 0) {
407 Glib::ustring q2(gcln +
":" + p.port_attr->port_name);
408 if (!p.port_attr->is_input) {
409 Glib::ustring sw = q1;
418 ret = jack_connect(gcl, q1.c_str(), q2.c_str());
420 ret = jack_disconnect(gcl, q1.c_str(), q2.c_str());
425 buf <<
"couldn't " << (v ?
"" :
"dis") <<
"connect " << q2 <<
" -> " << q1;
429 (*iter)[columns.connected] = v;
437 inline bool getnumber(
const Glib::ustring& p,
long *pi) {
439 *pi = strtol(p.c_str(), &q, 10);
443 int PortMapWindow::sort_func(
const Gtk::TreeModel::iterator& a,
const Gtk::TreeModel::iterator& b) {
444 Glib::ustring pa((*a)[columns.port]), pb((*b)[columns.port]);
447 if (pa[i] != pb[i]) {
458 return pa.compare(pb);
461 void PortMapWindow::load(
int sect, jack_port_t *jack_port) {
463 const unsigned int max_items_unfolded = 1;
464 PortSection& ps = portsection[sect];
465 Glib::RefPtr<Gtk::TreeStore> tree = ps.
treestore;
467 tree->set_sort_func(0, sigc::mem_fun(*
this, &PortMapWindow::sort_func));
468 tree->set_sort_column_id(0, Gtk::SORT_ASCENDING);
472 jack_client_t *gcl = (ps.port_attr->client_num == 0 ? jack.
client
474 if (jack.single_client) {
478 ports = jack_get_ports(gcl, NULL, ps.port_attr->port_type,
479 (ps.port_attr->is_input ? JackPortIsOutput : JackPortIsInput));
483 const char** conn_ports = jack_port_get_connections(jack_port);
484 ClientList cl(ports);
488 for (list<string>::iterator j = excluded_clients.begin(); j !=
489 excluded_clients.end(); ++j, idx++) {
490 if (!ps.port_attr->is_insert || ps.port_attr->client_num != idx) {
494 Gtk::TreeIter iter, parent, *parentp;
495 for (ClientList::iterator i = cl.begin(); i != cl.end(); ++i) {
496 ClientPortList *p = *i;
497 if (cl.size() > 1 && p->ports.size() > max_items_unfolded) {
498 parent = tree->append();
499 (*parent)[columns.port] = p->clientname();
500 (*parent)[columns.connected] =
false;
501 (*parent)[columns.is_port] =
false;
507 for (list<const char*>::iterator j = p->ports.begin(); j != p->ports.end(); ++j) {
511 for (
const char** q = conn_ports; *q; q++) {
512 if (strcmp(*q, *j) == 0) {
519 iter = tree->append((*parentp)->children());
521 iter = tree->append();
523 (*iter)[columns.port] = *j;
524 (*iter)[columns.connected] = conn;
525 (*iter)[columns.is_port] =
true;
530 update_summary(portsection[sect]);
534 void PortMapWindow::load_all() {
535 #define uslp() usleep(10); // prevents xruns?? (bug in jackd?)
544 #if defined(USE_MIDI_OUT) || defined(USE_MIDI_CC_OUT)
548 if (!jack.single_client) {
561 Glib::RefPtr<gx_gui::GxBuilder> bld = gx_gui::GxBuilder::create_from_file(
566 PortMapWindow::PortMapWindow(Glib::RefPtr<gx_gui::GxBuilder> bld,
gx_jack::GxJack& jack_, Glib::RefPtr<Gtk::AccelGroup> ag)
570 monitored_expander_child(0) {
571 bld->get_toplevel(
"PortMapWindow", window);
572 monitored_expander_child = 0;
576 excluded_clients.push_back(
string(jack.
client_name) +
":");
577 excluded_clients.push_back(
string(jack.
get_instancename()) +
"_meterbridge:");
578 excluded_clients.push_back(
string(
"jack_capture:"));
583 bld->find_widget(
"button1",b);
585 b->set_name(
"rack_button");
600 for (
int i = 0; i < number_of_ports; ++i) {
601 portsection[i].
port_attr = &gx_head_ports[i];
603 snprintf(name,
sizeof(name),
"scrolledwindow%d", i+1);
604 bld->find_widget(name, portsection[i].scrolled_window);
605 snprintf(name,
sizeof(name),
"treeview%d", i+1);
607 bld->find_widget(name, view);
608 Gtk::TreeViewColumn *col = view->get_column(0);
612 Gtk::CellRendererToggle *cell =
dynamic_cast<Gtk::CellRendererToggle*
>(col->get_first_cell_renderer());
614 portsection[i].
treestore = Gtk::TreeStore::create(columns);
615 view->set_model(portsection[i].treestore);
621 cell->signal_toggled().connect(
623 sigc::mem_fun(*
this, &PortMapWindow::on_cell_toggle),
624 sigc::ref(portsection[i])));
625 snprintf(name,
sizeof(name),
"expander%d", i+1);
627 if (portsection[i].expander) {
628 portsection[i].
expander->property_expanded().signal_changed().connect(
630 sigc::mem_fun(*
this, &PortMapWindow::on_expander),
631 sigc::ref(*portsection[i].expander)));
632 snprintf(name,
sizeof(name),
"port%d", i+1);
633 bld->find_widget(name, portsection[i].label);
639 window->add_accel_group(ag);
640 window->signal_check_resize().connect(sigc::mem_fun(*
this, &PortMapWindow::on_check_resize),
true);
643 bld->find_widget(
"notebook1",n);
645 t = n->get_nth_page(1);
646 if (jack.single_client) t->hide();
655 for (
int i = 0; i< number_of_ports; ++i) {
657 Glib::RefPtr<Gtk::TreeStore> tree = ps.
treestore;
659 tree->set_sort_func(0, sigc::mem_fun(*
this, &PortMapWindow::sort_func));
660 tree->set_sort_column_id(0, Gtk::SORT_ASCENDING);
662 update_summary(portsection[i]);