Fix boost signals (portability)
[ladish.git] / src / Patchage.cpp
blob377fc579feb49635e0131f87938e570a6c5b7680
1 /* This file is part of Patchage.
2 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
3 * Copyright (C) 2008 Nedko Arnaudov <nedko@arnaudov.name>
4 *
5 * Patchage is free software; you can redistribute it and/or modify it under the
6 * terms of the GNU General Public License as published by the Free Software
7 * Foundation; either version 2 of the License, or (at your option) any later
8 * version.
9 *
10 * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY
11 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <string.h>
20 #include <cmath>
21 #include <sstream>
22 #include <fstream>
23 #include <libgnomecanvasmm.h>
24 #include <libglademm/xml.h>
25 #include <gtk/gtkwindow.h>
26 #include <boost/format.hpp>
28 #include "config.h"
29 #include "common.hpp"
30 #include "jack_proxy.hpp"
31 #include "Patchage.hpp"
32 #include "PatchageCanvas.hpp"
33 #include "StateManager.hpp"
34 #include "lash_proxy.hpp"
35 #include "project_list.hpp"
36 #include "session.hpp"
37 #include "globals.hpp"
38 #include "a2j_proxy.hpp"
39 #include "PatchageModule.hpp"
40 #include "dbus_helpers.h"
41 #include "load_projects_dialog.hpp"
43 Patchage * g_app;
45 //#define LOG_TO_STD
46 #define LOG_TO_STATUS
48 using namespace std;
50 /* Gtk helpers (resize combo boxes) */
52 static void
53 gtkmm_get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
54 int& width,
55 int& height)
57 Pango::Rectangle ink_rect = layout->get_ink_extents ();
59 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
60 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
63 static void
64 gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text,
65 gint hpadding/*, gint vpadding*/)
68 int old_width, old_height;
69 w.get_size_request(old_width, old_height);
71 int width, height;
72 w.ensure_style ();
74 gtkmm_get_ink_pixel_size (w.create_pango_layout (text), width, height);
75 w.set_size_request(width + hpadding, old_height);//height + vpadding);
78 /* end Gtk helpers */
81 #define INIT_WIDGET(x) x(g_xml, ((const char*)#x) + 1)
83 Patchage::Patchage(int argc, char** argv)
84 : _max_dsp_load(0.0)
85 , INIT_WIDGET(_about_win)
86 , INIT_WIDGET(_buffer_size_combo)
87 , INIT_WIDGET(_clear_load_but)
88 , INIT_WIDGET(_main_scrolledwin)
89 , INIT_WIDGET(_main_win)
90 , INIT_WIDGET(_main_xrun_progress)
91 , INIT_WIDGET(_main_a2j_status_label)
92 , INIT_WIDGET(_main_lash_status_label)
93 , INIT_WIDGET(_menu_file_quit)
94 , INIT_WIDGET(_menu_help_about)
95 , INIT_WIDGET(_menu_jack_start)
96 , INIT_WIDGET(_menu_jack_stop)
97 , INIT_WIDGET(_menu_a2j_start)
98 , INIT_WIDGET(_menu_a2j_stop)
99 , INIT_WIDGET(_menu_lash_activate)
100 , INIT_WIDGET(_menu_lash_deactivate)
101 , INIT_WIDGET(_menu_load_project)
102 , INIT_WIDGET(_menu_save_all_projects)
103 , INIT_WIDGET(_menu_close_all_projects)
104 , INIT_WIDGET(_menu_store_positions)
105 , INIT_WIDGET(_menu_view_arrange)
106 , INIT_WIDGET(_menu_view_messages)
107 , INIT_WIDGET(_menu_view_projects)
108 , INIT_WIDGET(_menu_view_refresh)
109 , INIT_WIDGET(_menu_view_toolbar)
110 , INIT_WIDGET(_messages_clear_but)
111 , INIT_WIDGET(_messages_close_but)
112 , INIT_WIDGET(_messages_win)
113 , INIT_WIDGET(_project_list_viewport)
114 , INIT_WIDGET(_sample_rate_label)
115 , INIT_WIDGET(_status_text)
116 , INIT_WIDGET(_toolbar)
117 , INIT_WIDGET(_zoom_full_but)
118 , INIT_WIDGET(_zoom_normal_but)
120 g_app = this;
122 _settings_filename = getenv("HOME");
123 _settings_filename += "/." PATCHAGE_APPNAME "rc";
124 _state_manager = new StateManager();
125 _canvas = boost::shared_ptr<PatchageCanvas>(new PatchageCanvas(this, 1600*2, 1200*2));
127 while (argc > 0) {
128 if (!strcmp(*argv, "--help")) {
129 cout << "Usage: patchage [OPTIONS]\nOptions: --no-alsa" << endl;
130 exit(0);
133 argv++;
134 argc--;
137 patchage_dbus_init();
139 Glib::set_application_name("Patchage");
140 _about_win->property_program_name() = "Patchage";
141 _about_win->property_logo_icon_name() = PATCHAGE_APPNAME;
142 gtk_window_set_default_icon_name(PATCHAGE_APPNAME);
144 gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
146 _main_scrolledwin->add(*_canvas);
147 _canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320),
148 static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded
150 _main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
151 _main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
153 _main_scrolledwin->signal_scroll_event().connect(
154 sigc::mem_fun(this, &Patchage::on_scroll));
156 _buffer_size_combo->signal_changed().connect(
157 sigc::mem_fun(this, &Patchage::buffer_size_changed));
158 _clear_load_but->signal_clicked().connect(
159 sigc::mem_fun(this, &Patchage::clear_load));
160 _zoom_normal_but->signal_clicked().connect(sigc::bind(
161 sigc::mem_fun(this, &Patchage::zoom), 1.0));
162 _zoom_full_but->signal_clicked().connect(
163 sigc::mem_fun(_canvas.get(), &PatchageCanvas::zoom_full));
165 _menu_load_project->signal_activate().connect(
166 sigc::mem_fun(this, &Patchage::load_project_ask));
167 _menu_save_all_projects->signal_activate().connect(
168 sigc::mem_fun(this, &Patchage::save_all_projects));
169 _menu_close_all_projects->signal_activate().connect(
170 sigc::mem_fun(this, &Patchage::close_all_projects));
172 _menu_store_positions->signal_activate().connect(
173 sigc::mem_fun(this, &Patchage::on_store_positions));
174 _menu_file_quit->signal_activate().connect(
175 sigc::mem_fun(this, &Patchage::on_quit));
176 _menu_view_refresh->signal_activate().connect(
177 sigc::mem_fun(this, &Patchage::refresh));
178 _menu_view_arrange->signal_activate().connect(
179 sigc::mem_fun(this, &Patchage::on_arrange));
180 _menu_view_toolbar->signal_activate().connect(
181 sigc::mem_fun(this, &Patchage::on_view_toolbar));
182 _menu_view_messages->signal_toggled().connect(
183 sigc::mem_fun(this, &Patchage::on_show_messages));
184 _menu_view_projects->signal_toggled().connect(
185 sigc::mem_fun(this, &Patchage::on_show_projects));
186 _menu_help_about->signal_activate().connect(
187 sigc::mem_fun(this, &Patchage::on_help_about));
189 _messages_clear_but->signal_clicked().connect(
190 sigc::mem_fun(this, &Patchage::on_messages_clear));
191 _messages_close_but->signal_clicked().connect(
192 sigc::mem_fun(this, &Patchage::on_messages_close));
193 _messages_win->signal_delete_event().connect(
194 sigc::mem_fun(this, &Patchage::on_messages_delete));
196 _canvas->show();
197 _main_win->present();
199 _state_manager->load(_settings_filename);
201 _main_win->resize(
202 static_cast<int>(_state_manager->get_window_size().x),
203 static_cast<int>(_state_manager->get_window_size().y));
205 _main_win->move(
206 static_cast<int>(_state_manager->get_window_location().x),
207 static_cast<int>(_state_manager->get_window_location().y));
209 _about_win->set_transient_for(*_main_win);
211 _a2j = new a2j_proxy;
213 //info_msg(str(boost::format("a2j jack client name is '%s'") % _a2j->get_jack_client_name()));
215 _session = new session();
217 _project_list = new project_list(this, _session);
219 _lash = new lash_proxy(_session);
221 _jack = new jack_proxy(this);
223 _menu_jack_start->signal_activate().connect(
224 sigc::mem_fun(_jack, &jack_proxy::start_server));
225 _menu_jack_stop->signal_activate().connect(
226 sigc::mem_fun(_jack, &jack_proxy::stop_server));
228 _menu_a2j_start->signal_activate().connect(
229 sigc::mem_fun(_a2j, &a2j_proxy::start_bridge));
230 _menu_a2j_stop->signal_activate().connect(
231 sigc::mem_fun(_a2j, &a2j_proxy::stop_bridge));
233 _menu_lash_activate->signal_activate().connect(
234 sigc::mem_fun(_lash, &lash_proxy::try_activate));
235 _menu_lash_deactivate->signal_activate().connect(
236 sigc::mem_fun(_lash, &lash_proxy::deactivate));
238 jack_status_changed(_jack->is_started());
240 connect_widgets();
241 update_state();
243 _canvas->grab_focus();
245 // Idle callback, check if we need to refresh
246 Glib::signal_timeout().connect(
247 sigc::mem_fun(this, &Patchage::idle_callback), 100);
250 Patchage::~Patchage()
252 delete _jack;
253 delete _lash;
254 delete _project_list;
255 delete _session;
256 delete _state_manager;
257 delete _a2j;
259 _about_win.destroy();
260 _messages_win.destroy();
261 //_main_win.destroy();
263 patchage_dbus_uninit();
267 bool
268 Patchage::idle_callback()
270 update_load();
272 return true;
276 void
277 Patchage::update_toolbar()
279 bool started;
281 started = _jack->is_started();
283 _buffer_size_combo->set_sensitive(started);
285 if (started)
287 _buffer_size_combo->set_active((int)log2f(_jack->buffer_size()) - 5);
292 void
293 Patchage::update_load()
295 if (!_jack->is_started())
297 _main_xrun_progress->set_text("JACK stopped");
298 return;
301 char tmp_buf[8];
302 snprintf(tmp_buf, 8, "%zd", _jack->xruns());
304 _main_xrun_progress->set_text(string(tmp_buf) + " Dropouts");
306 float load = _jack->get_dsp_load();
308 load /= 100.0; // dbus returns it in percents, we use 0..1
310 if (load > _max_dsp_load)
312 _max_dsp_load = load;
313 _main_xrun_progress->set_fraction(load);
318 void
319 Patchage::zoom(double z)
321 _state_manager->set_zoom(z);
322 _canvas->set_zoom(z);
326 void
327 Patchage::refresh()
329 assert(_canvas);
331 _canvas->destroy();
333 if (_jack)
334 _jack->refresh();
336 for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
337 (*i)->resize();
342 /** Update the stored window location and size in the StateManager (in memory).
344 void
345 Patchage::store_window_location()
347 int loc_x, loc_y, size_x, size_y;
348 _main_win->get_position(loc_x, loc_y);
349 _main_win->get_size(size_x, size_y);
350 Coord window_location;
351 window_location.x = loc_x;
352 window_location.y = loc_y;
353 Coord window_size;
354 window_size.x = size_x;
355 window_size.y = size_y;
356 _state_manager->set_window_location(window_location);
357 _state_manager->set_window_size(window_size);
361 void
362 Patchage::clear_load()
364 _main_xrun_progress->set_fraction(0.0);
365 _jack->reset_xruns();
366 _max_dsp_load = 0.0;
370 void
371 Patchage::error_msg(const std::string& msg)
373 #if defined(LOG_TO_STATUS)
374 status_msg(msg);
375 #endif
376 #if defined(LOG_TO_STD)
377 cerr << msg << endl;
378 #endif
382 void
383 Patchage::info_msg(const std::string& msg)
385 #if defined(LOG_TO_STATUS)
386 status_msg(msg);
387 #endif
388 #if defined(LOG_TO_STD)
389 cerr << msg << endl;
390 #endif
394 void
395 Patchage::status_msg(const string& msg)
397 if (_status_text->get_buffer()->size() > 0)
398 _status_text->get_buffer()->insert(_status_text->get_buffer()->end(), "\n");
400 _status_text->get_buffer()->insert(_status_text->get_buffer()->end(), msg);
401 _status_text->scroll_to_mark(_status_text->get_buffer()->get_insert(), 0);
405 void
406 Patchage::update_state()
408 for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
409 shared_ptr<Module> module = dynamic_pointer_cast<Module>(*i);
410 if (module)
411 module->load_location();
416 /** Update the sensitivity status of menus to reflect the present.
418 * (eg. disable "Connect to Jack" when Patchage is already connected to Jack)
420 void
421 Patchage::connect_widgets()
423 _jack->signal_started.connect(
424 sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), true));
426 _jack->signal_stopped.connect(
427 sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), false));
430 void
431 Patchage::jack_status_changed(
432 bool started)
434 update_toolbar();
436 _menu_jack_start->set_sensitive(!started);
437 _menu_jack_stop->set_sensitive(started);
438 _clear_load_but->set_sensitive(started);
439 if (!started)
441 _main_xrun_progress->set_fraction(0.0);
445 void
446 Patchage::on_arrange()
448 assert(_canvas);
450 _canvas->arrange();
454 void
455 Patchage::on_help_about()
457 _about_win->run();
458 _about_win->hide();
462 void
463 Patchage::on_messages_clear()
465 _status_text->get_buffer()->erase(
466 _status_text->get_buffer()->begin(),
467 _status_text->get_buffer()->end());
471 void
472 Patchage::on_messages_close()
474 _menu_view_messages->set_active(false);
478 bool
479 Patchage::on_messages_delete(GdkEventAny*)
481 _menu_view_messages->set_active(false);
482 return true;
486 void
487 Patchage::on_quit()
489 _main_win->hide();
493 void
494 Patchage::on_show_messages()
496 if (_menu_view_messages->get_active())
497 _messages_win->present();
498 else
499 _messages_win->hide();
503 void
504 Patchage::on_show_projects()
506 if (_menu_view_projects->get_active())
507 _project_list_viewport->show();
508 else
509 _project_list_viewport->hide();
513 void
514 Patchage::on_store_positions()
516 store_window_location();
517 _state_manager->save(_settings_filename);
521 void
522 Patchage::on_view_toolbar()
524 if (_menu_view_toolbar->get_active())
525 _toolbar->show();
526 else
527 _toolbar->hide();
531 bool
532 Patchage::on_scroll(GdkEventScroll* ev)
534 cout << "ON SCROLL" << endl;
535 return false;
539 void
540 Patchage::buffer_size_changed()
542 const int selected = _buffer_size_combo->get_active_row_number();
544 if (selected == -1) {
545 update_toolbar();
546 } else {
547 uint32_t buffer_size = 1 << (selected+5);
549 // this check is temporal workaround for jack bug
550 // we skip setting buffer size if it same as acutal one
551 // proper place for such check is in jack
552 if (_jack->buffer_size() != buffer_size)
554 if (!_jack->set_buffer_size(buffer_size))
556 update_toolbar(); // reset combo box to actual value
562 void
563 Patchage::set_lash_availability(
564 bool lash_active)
566 _project_list->set_lash_availability(lash_active);
567 _menu_view_projects->set_active(lash_active);
568 _menu_lash_activate->set_sensitive(!lash_active);
569 _menu_lash_deactivate->set_sensitive(lash_active);
570 if (!lash_active)
572 _session->clear();
573 _main_lash_status_label->set_text("LASH N/A");
574 _project_list_viewport->hide();
576 else
578 _main_lash_status_label->set_text("LASH active");
579 _project_list_viewport->show();
583 void
584 Patchage::set_a2j_status(
585 unsigned int status)
587 const char * status_text;
589 switch (status)
591 case A2J_STATUS_NO_RESPONSE:
592 status_text = "A2J N/A";
593 _menu_a2j_start->set_sensitive(false);
594 _menu_a2j_stop->set_sensitive(false);
595 break;
596 case A2J_STATUS_BRIDGE_STOPPED:
597 status_text = "A2J bridge stopped";
598 _menu_a2j_start->set_sensitive(true);
599 _menu_a2j_stop->set_sensitive(false);
600 break;
601 case A2J_STATUS_BRIDGE_STARTED:
602 status_text = "A2J bridge started";
603 _menu_a2j_start->set_sensitive(false);
604 _menu_a2j_stop->set_sensitive(true);
605 break;
606 default:
607 error_msg(str(boost::format("Unknown A2J status %u") % status));
608 status_text = "Unknown A2J status";
609 _menu_a2j_start->set_sensitive(true);
610 _menu_a2j_stop->set_sensitive(true);
611 break;
614 _main_a2j_status_label->set_text(status_text);
617 void
618 Patchage::load_project_ask()
620 std::list<lash_project_info> projects;
622 _lash->get_available_projects(projects);
623 run_load_project_dialog(projects);
626 void
627 Patchage::load_project(
628 const std::string& project_name)
630 _lash->load_project(project_name);
633 void
634 Patchage::save_all_projects()
636 _lash->save_all_projects();
639 void
640 Patchage::save_project(
641 const std::string& project_name)
643 _lash->save_project(project_name);
646 void
647 Patchage::close_project(
648 const std::string& project_name)
650 _lash->close_project(project_name);
653 void
654 Patchage::close_all_projects()
656 _lash->close_all_projects();
659 void
660 Patchage::on_port_added(
661 const char * jack_client_name,
662 const char * jack_port_name,
663 PortType port_type,
664 bool is_input,
665 bool is_terminal)
667 bool is_a2j_mapped;
668 string canvas_client_name;
669 string canvas_port_name;
670 uint32_t alsa_client_id;
671 boost::shared_ptr<PatchageModule> module;
673 is_a2j_mapped = strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0;
674 if (is_a2j_mapped)
676 if (!_a2j->map_jack_port(jack_port_name, canvas_client_name, canvas_port_name, alsa_client_id))
678 return;
681 canvas_port_name = str(boost::format(canvas_port_name + " [a2j:%u]") % alsa_client_id);
683 else
685 canvas_client_name = jack_client_name;
686 canvas_port_name = jack_port_name;
689 ModuleType module_type = InputOutput;
690 if (_state_manager->get_module_split(canvas_client_name, is_terminal && !is_a2j_mapped)) {
691 if (is_input) {
692 module_type = Input;
693 } else {
694 module_type = Output;
698 module = _canvas->find_module(canvas_client_name, module_type);
699 if (!module) {
700 module = boost::shared_ptr<PatchageModule>(new PatchageModule(this, canvas_client_name, module_type));
701 module->load_location();
702 _canvas->add_item(module);
705 if (module->get_port(canvas_port_name)) {
706 return;
709 boost::shared_ptr<PatchagePort> port = boost::shared_ptr<PatchagePort>(
710 new PatchagePort(
711 module,
712 canvas_port_name,
713 is_input,
714 _state_manager->get_port_color(port_type)));
716 port->type = port_type;
717 port->is_a2j_mapped = is_a2j_mapped;
718 if (is_a2j_mapped)
720 port->a2j_jack_port_name = jack_port_name;
723 module->add_port(port);
725 module->resize();
728 boost::shared_ptr<PatchagePort>
729 Patchage::lookup_port(
730 const char * jack_client_name,
731 const char * jack_port_name)
733 if (strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0)
735 return _canvas->lookup_port_by_a2j_jack_port_name(jack_port_name);
738 return _canvas->get_port(jack_client_name, jack_port_name);
741 void
742 Patchage::on_port_removed(
743 const char * jack_client_name,
744 const char * jack_port_name)
746 boost::shared_ptr<PatchagePort> port = lookup_port(jack_client_name, jack_port_name);
747 if (!port) {
748 error_msg(str(boost::format("Unable to remove unknown port '%s':'%s'") % jack_client_name % jack_port_name));
749 return;
752 boost::shared_ptr<PatchageModule> module = dynamic_pointer_cast<PatchageModule>(port->module().lock());
754 module->remove_port(port);
755 port.reset();
757 // No empty modules (for now)
758 if (module->num_ports() == 0) {
759 _canvas->remove_item(module);
760 module.reset();
761 } else {
762 module->resize();
766 void
767 Patchage::on_ports_connected(
768 const char * jack_client1_name,
769 const char * jack_port1_name,
770 const char * jack_client2_name,
771 const char * jack_port2_name)
773 boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
774 if (!port1) {
775 error_msg((string)"Unable to connect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
776 return;
779 boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
780 if (!port2) {
781 error_msg((string)"Unable to connect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
782 return;
785 _canvas->add_connection(port1, port2, port1->color() + 0x22222200);
788 void
789 Patchage::on_ports_disconnected(
790 const char * jack_client1_name,
791 const char * jack_port1_name,
792 const char * jack_client2_name,
793 const char * jack_port2_name)
795 boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
796 if (!port1) {
797 error_msg((string)"Unable to disconnect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
798 return;
801 boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
802 if (!port2) {
803 error_msg((string)"Unable to disconnect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
804 return;
807 _canvas->remove_connection(port1, port2);
810 static
811 bool
812 port_type_match(
813 boost::shared_ptr<PatchagePort> port1,
814 boost::shared_ptr<PatchagePort> port2)
816 return port1->type == port2->type;
819 void
820 Patchage::get_port_jack_names(
821 boost::shared_ptr<PatchagePort> port,
822 string& jack_client_name,
823 string& jack_port_name)
825 if (port->is_a2j_mapped)
827 jack_client_name = _a2j->get_jack_client_name();
828 jack_port_name = port->a2j_jack_port_name;
830 else
832 jack_client_name = port->module().lock()->name();
833 jack_port_name = port->name();
837 void
838 Patchage::connect(
839 boost::shared_ptr<PatchagePort> port1,
840 boost::shared_ptr<PatchagePort> port2)
842 string jack_client1_name;
843 string jack_port1_name;
844 string jack_client2_name;
845 string jack_port2_name;
847 if (port_type_match(port1, port2))
849 get_port_jack_names(port1, jack_client1_name, jack_port1_name);
850 get_port_jack_names(port2, jack_client2_name, jack_port2_name);
852 _jack->connect(
853 jack_client1_name.c_str(),
854 jack_port1_name.c_str(),
855 jack_client2_name.c_str(),
856 jack_port2_name.c_str());
858 else
860 status_msg("ERROR: Attempt to connect ports with mismatched types");
864 void
865 Patchage::disconnect(
866 boost::shared_ptr<PatchagePort> port1,
867 boost::shared_ptr<PatchagePort> port2)
869 string jack_client1_name;
870 string jack_port1_name;
871 string jack_client2_name;
872 string jack_port2_name;
874 if (port_type_match(port1, port2))
876 get_port_jack_names(port1, jack_client1_name, jack_port1_name);
877 get_port_jack_names(port2, jack_client2_name, jack_port2_name);
879 _jack->disconnect(
880 jack_client1_name.c_str(),
881 jack_port1_name.c_str(),
882 jack_client2_name.c_str(),
883 jack_port2_name.c_str());
885 else
887 status_msg("ERROR: Attempt to disconnect ports with mismatched types");
891 /** Destroy all JACK (canvas) ports.
893 void
894 Patchage::clear_canvas()
896 ItemList modules = _canvas->items(); // copy
897 for (ItemList::iterator m = modules.begin(); m != modules.end(); ++m) {
898 shared_ptr<Module> module = dynamic_pointer_cast<Module>(*m);
899 if (!module)
900 continue;
902 PortVector ports = module->ports(); // copy
903 for (PortVector::iterator p = ports.begin(); p != ports.end(); ++p) {
904 boost::shared_ptr<PatchagePort> port = boost::dynamic_pointer_cast<PatchagePort>(*p);
905 if (port)
907 module->remove_port(port);
908 port->hide();
912 if (module->ports().empty())
913 _canvas->remove_item(module);
914 else
915 module->resize();
919 bool
920 Patchage::is_canvas_empty()
922 return _canvas->items().empty();