patchbay interface
[ladish.git] / gui / main.c
blobef6a234fbcbbc1aa8958d73d943d0cb49d514266
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
8 **************************************************************************
9 * This file contains the code that implements main() and other top-level functionality
10 **************************************************************************
12 * LADI Session Handler is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * LADI Session Handler is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
24 * or write to the Free Software Foundation, Inc.,
25 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "common.h"
29 #include "glade.h"
30 #include "canvas.h"
31 #include "graph_canvas.h"
32 #include "../jack_proxy.h"
33 #include "dbus_helpers.h"
34 #include "control_proxy.h"
36 #if 0
37 class Patchage {
38 public:
39 Patchage();
40 ~Patchage();
42 Gtk::Window* window() { return _main_win.get(); }
44 void quit() { _main_win->hide(); }
46 void refresh();
48 void clear_load();
49 void update_state();
51 void set_studio_availability(bool available);
52 #if 0
53 void set_a2j_status(unsigned int status);
55 void load_project_ask();
56 void load_project(const std::string& project_name);
57 void save_all_projects();
58 void save_project(const std::string& project_name);
59 void close_project(const std::string& project_name);
60 void close_all_projects();
61 #endif
63 protected:
64 void connect_widgets();
66 void on_arrange();
67 void on_help_about();
68 void on_quit();
69 void on_show_projects();
70 void on_view_toolbar();
71 bool on_scroll(GdkEventScroll* ev);
73 void zoom(double z);
74 bool idle_callback();
75 void update_load();
76 void update_toolbar();
78 void jack_status_changed(bool started);
80 void buffer_size_changed();
82 #if 0
83 void
84 get_port_jack_names(
85 boost::shared_ptr<PatchagePort> port,
86 std::string& jack_client_name,
87 std::string& jack_port_name);
89 boost::shared_ptr<PatchagePort>
90 lookup_port(
91 const char * jack_client_name,
92 const char * jack_port_name);
93 #endif
95 //a2j_proxy * _a2j;
96 //session * _session;
97 //lash_proxy * _lash;
98 //project_list * _project_list;
100 Gtk::Main* _gtk_main;
102 float _max_dsp_load;
104 Widget<Gtk::AboutDialog> _about_win;
105 Widget<Gtk::ComboBox> _buffer_size_combo;
106 Widget<Gtk::ToolButton> _clear_load_but;
107 Widget<Gtk::ScrolledWindow> _main_scrolledwin;
108 Widget<Gtk::Window> _main_win;
109 Widget<Gtk::ProgressBar> _main_xrun_progress;
110 Widget<Gtk::Label> _main_a2j_status_label;
111 Widget<Gtk::MenuItem> _menu_file_quit;
112 Widget<Gtk::MenuItem> _menu_help_about;
113 Widget<Gtk::MenuItem> _menu_jack_start;
114 Widget<Gtk::MenuItem> _menu_jack_stop;
115 Widget<Gtk::MenuItem> _menu_a2j_start;
116 Widget<Gtk::MenuItem> _menu_a2j_stop;
117 Widget<Gtk::MenuItem> _menu_load_project;
118 Widget<Gtk::MenuItem> _menu_save_all_projects;
119 Widget<Gtk::MenuItem> _menu_close_all_projects;
120 Widget<Gtk::MenuItem> _menu_store_positions;
121 Widget<Gtk::MenuItem> _menu_view_arrange;
122 Widget<Gtk::CheckMenuItem> _menu_view_projects;
123 Widget<Gtk::MenuItem> _menu_view_refresh;
124 Widget<Gtk::CheckMenuItem> _menu_view_toolbar;
125 Widget<Gtk::Viewport> _project_list_viewport;
126 Widget<Gtk::Label> _sample_rate_label;
127 Widget<Gtk::Toolbar> _toolbar;
128 Widget<Gtk::ToolButton> _zoom_full_but;
129 Widget<Gtk::ToolButton> _zoom_normal_but;
132 #include "globals.hpp"
134 #include "common.h"
135 #include "Widget.hpp"
136 #include <gtkmm.h>
138 #include "common.h"
140 #include <string.h>
141 #include <cmath>
142 #include <libgnomecanvasmm.h>
143 #include <libglademm/xml.h>
144 #include <gtk/gtkwindow.h>
145 #include <boost/format.hpp>
147 #include "project_list.hpp"
148 #include "session.hpp"
149 #include "globals.hpp"
150 //#include "load_projects_dialog.hpp"
151 #include "graph_canvas.h"
152 #include "../jack_proxy.h"
154 Patchage * g_app;
156 #define LOG_TO_STD
157 //#define LOG_TO_STATUS
159 /* Gtk helpers (resize combo boxes) */
161 static void
162 gtkmm_get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
163 int& width,
164 int& height)
166 Pango::Rectangle ink_rect = layout->get_ink_extents ();
168 width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
169 height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
172 static void
173 gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text,
174 gint hpadding/*, gint vpadding*/)
177 int old_width, old_height;
178 w.get_size_request(old_width, old_height);
180 int width, height;
181 w.ensure_style ();
183 gtkmm_get_ink_pixel_size (w.create_pango_layout (text), width, height);
184 w.set_size_request(width + hpadding, old_height);//height + vpadding);
187 /* end Gtk helpers */
190 #define INIT_WIDGET(x) x(g_xml, ((const char*)#x) + 1)
192 Patchage::Patchage()
193 : _max_dsp_load(0.0)
194 #if 0
195 , INIT_WIDGET(_about_win)
196 , INIT_WIDGET(_buffer_size_combo)
197 , INIT_WIDGET(_clear_load_but)
198 , INIT_WIDGET(_main_scrolledwin)
199 , INIT_WIDGET(_main_win)
200 , INIT_WIDGET(_main_xrun_progress)
201 , INIT_WIDGET(_main_a2j_status_label)
202 , INIT_WIDGET(_menu_file_quit)
203 , INIT_WIDGET(_menu_help_about)
204 , INIT_WIDGET(_menu_jack_start)
205 , INIT_WIDGET(_menu_jack_stop)
206 , INIT_WIDGET(_menu_a2j_start)
207 , INIT_WIDGET(_menu_a2j_stop)
208 , INIT_WIDGET(_menu_load_project)
209 , INIT_WIDGET(_menu_save_all_projects)
210 , INIT_WIDGET(_menu_close_all_projects)
211 , INIT_WIDGET(_menu_store_positions)
212 , INIT_WIDGET(_menu_view_arrange)
213 , INIT_WIDGET(_menu_view_projects)
214 , INIT_WIDGET(_menu_view_refresh)
215 , INIT_WIDGET(_menu_view_toolbar)
216 , INIT_WIDGET(_project_list_viewport)
217 , INIT_WIDGET(_sample_rate_label)
218 , INIT_WIDGET(_toolbar)
219 , INIT_WIDGET(_zoom_full_but)
220 , INIT_WIDGET(_zoom_normal_but)
221 #endif
223 g_app = this;
225 patchage_dbus_init();
227 graph_create(JACKDBUS_SERVICE, JACKDBUS_OBJECT, &g_jack_graph);
228 graph_canvas_create(1600 * 2, 1200 * 2, &g_jack_graph_canvas);
229 graph_canvas_attach(g_jack_graph_canvas, g_jack_graph);
230 graph_activate(g_jack_graph);
232 Glib::set_application_name("Patchage");
233 _about_win->property_program_name() = "Patchage";
234 _about_win->property_logo_icon_name() = "gladish";
235 gtk_window_set_default_icon_name("gladish");
237 gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
239 _main_scrolledwin->add(*Glib::wrap(canvas_get_widget(graph_canvas_get_canvas(g_jack_graph_canvas))));
241 // _canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320),
242 // static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded
244 _main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
245 _main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
247 _main_scrolledwin->signal_scroll_event().connect(
248 sigc::mem_fun(this, &Patchage::on_scroll));
250 _buffer_size_combo->signal_changed().connect(
251 sigc::mem_fun(this, &Patchage::buffer_size_changed));
252 _clear_load_but->signal_clicked().connect(
253 sigc::mem_fun(this, &Patchage::clear_load));
254 _zoom_normal_but->signal_clicked().connect(sigc::bind(
255 sigc::mem_fun(this, &Patchage::zoom), 1.0));
256 // _zoom_full_but->signal_clicked().connect(sigc::mem_fun(_canvas.get(), &PatchageCanvas::zoom_full));
258 // _menu_load_project->signal_activate().connect(sigc::mem_fun(this, &Patchage::load_project_ask));
259 // _menu_save_all_projects->signal_activate().connect(sigc::mem_fun(this, &Patchage::save_all_projects));
260 // _menu_close_all_projects->signal_activate().connect(sigc::mem_fun(this, &Patchage::close_all_projects));
262 _menu_file_quit->signal_activate().connect(
263 sigc::mem_fun(this, &Patchage::on_quit));
264 _menu_view_refresh->signal_activate().connect(
265 sigc::mem_fun(this, &Patchage::refresh));
266 _menu_view_arrange->signal_activate().connect(
267 sigc::mem_fun(this, &Patchage::on_arrange));
268 _menu_view_toolbar->signal_activate().connect(
269 sigc::mem_fun(this, &Patchage::on_view_toolbar));
270 _menu_view_projects->signal_toggled().connect(
271 sigc::mem_fun(this, &Patchage::on_show_projects));
272 _menu_help_about->signal_activate().connect(
273 sigc::mem_fun(this, &Patchage::on_help_about));
275 Glib::wrap(canvas_get_widget(graph_canvas_get_canvas(g_jack_graph_canvas)))->show();
276 _main_win->present();
278 _about_win->set_transient_for(*_main_win);
280 // _a2j = new a2j_proxy;
282 //info_msg(str(boost::format("a2j jack client name is '%s'") % _a2j->get_jack_client_name()));
284 // _session = new session();
286 // _project_list = new project_list(this, _session);
287 // _project_list_viewport->hide();
289 // _lash = new lash_proxy(_session);
291 //_menu_jack_start->signal_activate().connect(sigc::mem_fun(_jack, &jack_proxy::start_server));
292 //_menu_jack_stop->signal_activate().connect(sigc::mem_fun(_jack, &jack_proxy::stop_server));
294 // _menu_a2j_start->signal_activate().connect(sigc::mem_fun(_a2j, &a2j_proxy::start_bridge));
295 // _menu_a2j_stop->signal_activate().connect(sigc::mem_fun(_a2j, &a2j_proxy::stop_bridge));
297 //jack_status_changed(_jack->is_started());
299 connect_widgets();
300 update_state();
302 // _canvas->grab_focus();
304 // Idle callback, check if we need to refresh
305 Glib::signal_timeout().connect(
306 sigc::mem_fun(this, &Patchage::idle_callback), 100);
309 Patchage::~Patchage()
311 //delete _lash;
312 //delete _project_list;
313 //delete _session;
314 //delete _a2j;
316 _about_win.destroy();
317 //_main_win.destroy();
319 patchage_dbus_uninit();
322 bool
323 Patchage::idle_callback()
325 update_load();
327 return true;
330 void
331 Patchage::update_toolbar()
333 #if 0
334 bool started;
336 started = _jack->is_started();
338 _buffer_size_combo->set_sensitive(started);
340 if (started)
342 _buffer_size_combo->set_active((int)log2f(_jack->buffer_size()) - 5);
344 #endif
347 void
348 Patchage::update_load()
350 #if 0
351 if (!_jack->is_started())
353 _main_xrun_progress->set_text("JACK stopped");
354 return;
357 char tmp_buf[8];
358 snprintf(tmp_buf, 8, "%zd", _jack->xruns());
360 _main_xrun_progress->set_text(std::string(tmp_buf) + " Dropouts");
362 float load = _jack->get_dsp_load();
364 load /= 100.0; // dbus returns it in percents, we use 0..1
366 if (load > _max_dsp_load)
368 _max_dsp_load = load;
369 _main_xrun_progress->set_fraction(load);
371 #endif
375 void
376 Patchage::zoom(double z)
378 // _canvas->set_zoom(z);
382 void
383 Patchage::refresh()
385 // assert(_canvas);
387 // _canvas->destroy();
389 // if (_jack)
390 // _jack->refresh();
392 // for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
393 // (*i)->resize();
394 // }
397 void
398 Patchage::clear_load()
400 #if 0
401 _main_xrun_progress->set_fraction(0.0);
402 _jack->reset_xruns();
403 _max_dsp_load = 0.0;
404 #endif
407 void
408 Patchage::update_state()
410 // for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
411 // shared_ptr<Module> module = dynamic_pointer_cast<Module>(*i);
412 // if (module)
413 // module->load_location();
414 // }
418 /** Update the sensitivity status of menus to reflect the present.
420 * (eg. disable "Connect to Jack" when Patchage is already connected to Jack)
422 void
423 Patchage::connect_widgets()
425 //_jack->signal_started.connect(sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), true));
426 //_jack->signal_stopped.connect(sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), false));
429 void
430 Patchage::jack_status_changed(
431 bool started)
433 update_toolbar();
435 _menu_jack_start->set_sensitive(!started);
436 _menu_jack_stop->set_sensitive(started);
437 _clear_load_but->set_sensitive(started);
438 if (!started)
440 _main_xrun_progress->set_fraction(0.0);
444 void
445 Patchage::on_arrange()
447 // assert(_canvas);
449 // _canvas->arrange();
453 void
454 Patchage::on_help_about()
456 _about_win->run();
457 _about_win->hide();
461 void
462 Patchage::on_quit()
464 _main_win->hide();
467 void
468 Patchage::on_show_projects()
470 if (_menu_view_projects->get_active())
471 _project_list_viewport->show();
472 else
473 _project_list_viewport->hide();
476 void
477 Patchage::on_view_toolbar()
479 if (_menu_view_toolbar->get_active())
480 _toolbar->show();
481 else
482 _toolbar->hide();
486 bool
487 Patchage::on_scroll(GdkEventScroll* ev)
489 lash_debug("ON SCROLL");
490 return false;
494 void
495 Patchage::buffer_size_changed()
497 #if 0
498 const int selected = _buffer_size_combo->get_active_row_number();
500 if (selected == -1)
502 update_toolbar();
504 else
506 uint32_t buffer_size = 1 << (selected+5);
508 // this check is temporal workaround for jack bug
509 // we skip setting buffer size if it same as acutal one
510 // proper place for such check is in jack
511 if (_jack->buffer_size() != buffer_size)
513 if (!_jack->set_buffer_size(buffer_size))
515 update_toolbar(); // reset combo box to actual value
519 #endif
522 void
523 Patchage::set_studio_availability(
524 bool available)
526 if (available)
528 _main_win->set_title("Active Studio - LADI Session Handler");
530 else
532 _main_win->set_title("LADI Session Handler");
534 //_project_list->set_lash_availability(available);
535 _menu_view_projects->set_active(available);
538 #if 0
539 void
540 Patchage::set_a2j_status(
541 unsigned int status)
543 const char * status_text;
545 switch (status)
547 case A2J_STATUS_NO_RESPONSE:
548 status_text = "A2J N/A";
549 _menu_a2j_start->set_sensitive(false);
550 _menu_a2j_stop->set_sensitive(false);
551 break;
552 case A2J_STATUS_BRIDGE_STOPPED:
553 status_text = "A2J bridge stopped";
554 _menu_a2j_start->set_sensitive(true);
555 _menu_a2j_stop->set_sensitive(false);
556 break;
557 case A2J_STATUS_BRIDGE_STARTED:
558 status_text = "A2J bridge started";
559 _menu_a2j_start->set_sensitive(false);
560 _menu_a2j_stop->set_sensitive(true);
561 break;
562 default:
563 error_msg(str(boost::format("Unknown A2J status %u") % status));
564 status_text = "Unknown A2J status";
565 _menu_a2j_start->set_sensitive(true);
566 _menu_a2j_stop->set_sensitive(true);
567 break;
570 _main_a2j_status_label->set_text(status_text);
573 void
574 Patchage::load_project_ask()
576 std::list<lash_project_info> projects;
578 _lash->get_available_projects(projects);
579 run_load_project_dialog(projects);
582 void
583 Patchage::load_project(
584 const std::string& project_name)
586 _lash->load_project(project_name);
589 void
590 Patchage::save_all_projects()
592 _lash->save_all_projects();
595 void
596 Patchage::save_project(
597 const std::string& project_name)
599 _lash->save_project(project_name);
602 void
603 Patchage::close_project(
604 const std::string& project_name)
606 _lash->close_project(project_name);
609 void
610 Patchage::close_all_projects()
612 _lash->close_all_projects();
615 void
616 Patchage::on_port_added(
617 const char * jack_client_name,
618 const char * jack_port_name,
619 PortType port_type,
620 bool is_input,
621 bool is_terminal)
623 bool is_a2j_mapped;
624 std::string canvas_client_name;
625 std::string canvas_port_name;
626 uint32_t alsa_client_id;
627 boost::shared_ptr<PatchageModule> module;
629 is_a2j_mapped = strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0;
630 if (is_a2j_mapped)
632 if (!_a2j->map_jack_port(jack_port_name, canvas_client_name, canvas_port_name, alsa_client_id))
634 return;
637 canvas_port_name = str(boost::format(canvas_port_name + " [a2j:%u]") % alsa_client_id);
639 else
641 canvas_client_name = jack_client_name;
642 canvas_port_name = jack_port_name;
645 ModuleType module_type = InputOutput;
646 if (_state_manager->get_module_split(canvas_client_name, is_terminal && !is_a2j_mapped)) {
647 if (is_input) {
648 module_type = Input;
649 } else {
650 module_type = Output;
654 module = _canvas->find_module(canvas_client_name, module_type);
655 if (!module) {
656 module = boost::shared_ptr<PatchageModule>(new PatchageModule(this, canvas_client_name, module_type));
657 module->load_location();
658 _canvas->add_item(module);
661 if (module->get_port(canvas_port_name)) {
662 return;
665 boost::shared_ptr<PatchagePort> port = boost::shared_ptr<PatchagePort>(
666 new PatchagePort(
667 module,
668 canvas_port_name,
669 is_input,
670 _state_manager->get_port_color(port_type)));
672 port->type = port_type;
673 port->is_a2j_mapped = is_a2j_mapped;
674 if (is_a2j_mapped)
676 port->a2j_jack_port_name = jack_port_name;
679 module->add_port(port);
681 module->resize();
684 boost::shared_ptr<PatchagePort>
685 Patchage::lookup_port(
686 const char * jack_client_name,
687 const char * jack_port_name)
689 if (strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0)
691 return _canvas->lookup_port_by_a2j_jack_port_name(jack_port_name);
694 return _canvas->get_port(jack_client_name, jack_port_name);
697 void
698 Patchage::on_port_removed(
699 const char * jack_client_name,
700 const char * jack_port_name)
702 boost::shared_ptr<PatchagePort> port = lookup_port(jack_client_name, jack_port_name);
703 if (!port) {
704 error_msg(str(boost::format("Unable to remove unknown port '%s':'%s'") % jack_client_name % jack_port_name));
705 return;
708 boost::shared_ptr<PatchageModule> module = dynamic_pointer_cast<PatchageModule>(port->module().lock());
710 module->remove_port(port);
711 port.reset();
713 // No empty modules (for now)
714 if (module->num_ports() == 0) {
715 _canvas->remove_item(module);
716 module.reset();
717 } else {
718 module->resize();
722 void
723 Patchage::on_ports_connected(
724 const char * jack_client1_name,
725 const char * jack_port1_name,
726 const char * jack_client2_name,
727 const char * jack_port2_name)
729 boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
730 if (!port1) {
731 error_msg((std::string)"Unable to connect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
732 return;
735 boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
736 if (!port2) {
737 error_msg((std::string)"Unable to connect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
738 return;
741 _canvas->add_connection(port1, port2, port1->color() + 0x22222200);
744 void
745 Patchage::on_ports_disconnected(
746 const char * jack_client1_name,
747 const char * jack_port1_name,
748 const char * jack_client2_name,
749 const char * jack_port2_name)
751 boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
752 if (!port1) {
753 error_msg((std::string)"Unable to disconnect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
754 return;
757 boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
758 if (!port2) {
759 error_msg((std::string)"Unable to disconnect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
760 return;
763 _canvas->remove_connection(port1, port2);
766 static
767 bool
768 port_type_match(
769 boost::shared_ptr<PatchagePort> port1,
770 boost::shared_ptr<PatchagePort> port2)
772 return port1->type == port2->type;
775 void
776 Patchage::get_port_jack_names(
777 boost::shared_ptr<PatchagePort> port,
778 std::string& jack_client_name,
779 std::string& jack_port_name)
781 if (port->is_a2j_mapped)
783 jack_client_name = _a2j->get_jack_client_name();
784 jack_port_name = port->a2j_jack_port_name;
786 else
788 jack_client_name = port->module().lock()->name();
789 jack_port_name = port->name();
793 void
794 Patchage::connect(
795 boost::shared_ptr<PatchagePort> port1,
796 boost::shared_ptr<PatchagePort> port2)
798 std::string jack_client1_name;
799 std::string jack_port1_name;
800 std::string jack_client2_name;
801 std::string jack_port2_name;
803 if (port_type_match(port1, port2))
805 get_port_jack_names(port1, jack_client1_name, jack_port1_name);
806 get_port_jack_names(port2, jack_client2_name, jack_port2_name);
808 _jack->connect(
809 jack_client1_name.c_str(),
810 jack_port1_name.c_str(),
811 jack_client2_name.c_str(),
812 jack_port2_name.c_str());
814 else
816 status_msg("ERROR: Attempt to connect ports with mismatched types");
820 void
821 Patchage::disconnect(
822 boost::shared_ptr<PatchagePort> port1,
823 boost::shared_ptr<PatchagePort> port2)
825 std::string jack_client1_name;
826 std::string jack_port1_name;
827 std::string jack_client2_name;
828 std::string jack_port2_name;
830 if (port_type_match(port1, port2))
832 get_port_jack_names(port1, jack_client1_name, jack_port1_name);
833 get_port_jack_names(port2, jack_client2_name, jack_port2_name);
835 _jack->disconnect(
836 jack_client1_name.c_str(),
837 jack_port1_name.c_str(),
838 jack_client2_name.c_str(),
839 jack_port2_name.c_str());
841 else
843 status_msg("ERROR: Attempt to disconnect ports with mismatched types");
847 bool
848 Patchage::is_canvas_empty()
850 return _canvas->items().empty();
852 #endif
853 #endif
855 GtkScrolledWindow * g_main_scrolledwin;
857 struct view
859 char * name;
860 graph_canvas_handle graph_canvas;
861 graph_handle graph;
862 GtkWidget * canvas_widget;
865 struct view * create_view(const char * name, const char * service, const char * object)
867 struct view * view_ptr;
869 view_ptr = malloc(sizeof(struct view));
870 if (view_ptr == NULL)
872 lash_error("malloc() failed for struct view");
873 goto fail;
876 view_ptr->name = strdup(name);
877 if (view_ptr->name == NULL)
879 lash_error("strdup() failed for \"%s\"", name);
880 goto free_view;
883 if (!graph_create(JACKDBUS_SERVICE, JACKDBUS_OBJECT, &view_ptr->graph))
885 goto free_name;
888 if (!graph_canvas_create(1600 * 2, 1200 * 2, &view_ptr->graph_canvas))
890 goto destroy_graph;
893 if (!graph_canvas_attach(view_ptr->graph_canvas, view_ptr->graph))
895 goto destroy_graph_canvas;
898 if (!graph_activate(view_ptr->graph))
900 goto detach_graph_canvas;
903 view_ptr->canvas_widget = canvas_get_widget(graph_canvas_get_canvas(view_ptr->graph_canvas));
905 gtk_widget_show(view_ptr->canvas_widget);
907 return view_ptr;
909 detach_graph_canvas:
910 graph_canvas_detach(view_ptr->graph_canvas);
911 destroy_graph_canvas:
912 graph_canvas_destroy(view_ptr->graph_canvas);
913 destroy_graph:
914 graph_destroy(view_ptr->graph);
915 free_name:
916 free(view_ptr->name);
917 free_view:
918 free(view_ptr);
919 fail:
920 return NULL;
923 void destroy_view(struct view * view_ptr)
925 graph_canvas_detach(view_ptr->graph_canvas);
926 graph_canvas_destroy(view_ptr->graph_canvas);
927 graph_destroy(view_ptr->graph);
928 free(view_ptr->name);
929 free(view_ptr);
932 struct view * g_jack_view;
934 void control_proxy_on_studio_appeared(void)
936 g_jack_view = create_view("Raw JACK", JACKDBUS_SERVICE, JACKDBUS_OBJECT);
938 gtk_container_add(GTK_CONTAINER(g_main_scrolledwin), g_jack_view->canvas_widget);
940 //_canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320), static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded
941 //_main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
942 //_main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
945 void control_proxy_on_studio_disappeared(void)
947 gtk_container_remove(GTK_CONTAINER(g_main_scrolledwin), g_jack_view->canvas_widget);
948 destroy_view(g_jack_view);
951 int main(int argc, char** argv)
953 GtkWidget * main_win;
955 gtk_init(&argc, &argv);
957 if (!canvas_init())
959 lash_error("Canvas initialization failed.");
960 return 1;
963 if (!init_glade())
965 return 1;
968 /* Obtain widgets that we need */
969 main_win = get_glade_widget("main_win");
970 g_main_scrolledwin = GTK_SCROLLED_WINDOW(get_glade_widget("main_scrolledwin"));
972 patchage_dbus_init();
974 if (!control_proxy_init())
976 return 1;
979 //gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
981 g_signal_connect(G_OBJECT(main_win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
982 g_signal_connect(G_OBJECT(get_glade_widget("menu_file_quit")), "activate", G_CALLBACK(gtk_main_quit), NULL);
984 gtk_widget_show(main_win);
986 //_about_win->set_transient_for(*_main_win);
988 gtk_main();
990 control_proxy_uninit();
991 uninit_glade();
993 return 0;