root/gui/main.c @ 4bc224e2b8433fb8a66be281428a0c4b8edcb29d

Revision 4bc224e2b8433fb8a66be281428a0c4b8edcb29d, 24.6 KB (checked in by Nedko Arnaudov <nedko@…>, 4 years ago)

Two views, one for raw jack and one for studio

  • Property mode set to 100644
Line 
1/* -*- Mode: C ; c-basic-offset: 2 -*- */
2/*
3 * LADI Session Handler (ladish)
4 *
5 * Copyright (C) 2008, 2009 Nedko Arnaudov <nedko@arnaudov.name>
6 * Copyright (C) 2007 Dave Robillard <http://drobilla.net>
7 *
8 **************************************************************************
9 * This file contains the code that implements main() and other top-level functionality
10 **************************************************************************
11 *
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.
16 *
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.
21 *
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.
26 */
27
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"
35#include "../dbus_constants.h"
36
37#if 0
38class Patchage {
39public:
40  Patchage();
41  ~Patchage();
42
43  Gtk::Window* window() { return _main_win.get(); }
44 
45  void quit() { _main_win->hide(); }
46
47  void        refresh();
48
49  void clear_load();
50  void update_state();
51 
52  void set_studio_availability(bool available);
53#if 0
54  void set_a2j_status(unsigned int status);
55
56  void load_project_ask();
57  void load_project(const std::string& project_name);
58  void save_all_projects();
59  void save_project(const std::string& project_name);
60  void close_project(const std::string& project_name);
61  void close_all_projects();
62#endif
63
64protected:
65  void connect_widgets();
66
67  void on_arrange();
68  void on_help_about();
69  void on_quit();
70  void on_show_projects();
71  void on_view_toolbar();
72  bool on_scroll(GdkEventScroll* ev);
73
74  void zoom(double z);
75  bool idle_callback();
76  void update_load();
77  void update_toolbar();
78
79  void jack_status_changed(bool started);
80
81  void buffer_size_changed();
82
83#if 0
84  void
85  get_port_jack_names(
86    boost::shared_ptr<PatchagePort> port,
87    std::string& jack_client_name,
88    std::string& jack_port_name);
89 
90  boost::shared_ptr<PatchagePort>
91  lookup_port(
92    const char * jack_client_name,
93    const char * jack_port_name);
94#endif
95
96  //a2j_proxy * _a2j;
97  //session * _session;
98  //lash_proxy * _lash;
99  //project_list * _project_list;
100
101  Gtk::Main* _gtk_main;
102
103  float _max_dsp_load;
104 
105  Widget<Gtk::AboutDialog>    _about_win;
106  Widget<Gtk::ComboBox>       _buffer_size_combo;
107  Widget<Gtk::ToolButton>     _clear_load_but;
108  Widget<Gtk::ScrolledWindow> _main_scrolledwin;
109  Widget<Gtk::Window>         _main_win;
110  Widget<Gtk::ProgressBar>    _main_xrun_progress;
111  Widget<Gtk::Label>          _main_a2j_status_label;
112  Widget<Gtk::MenuItem>       _menu_file_quit;
113  Widget<Gtk::MenuItem>       _menu_help_about;
114  Widget<Gtk::MenuItem>       _menu_jack_start;
115  Widget<Gtk::MenuItem>       _menu_jack_stop;
116  Widget<Gtk::MenuItem>       _menu_a2j_start;
117  Widget<Gtk::MenuItem>       _menu_a2j_stop;
118  Widget<Gtk::MenuItem>       _menu_load_project;
119  Widget<Gtk::MenuItem>       _menu_save_all_projects;
120  Widget<Gtk::MenuItem>       _menu_close_all_projects;
121  Widget<Gtk::MenuItem>       _menu_store_positions;
122  Widget<Gtk::MenuItem>       _menu_view_arrange;
123  Widget<Gtk::CheckMenuItem>  _menu_view_projects;
124  Widget<Gtk::MenuItem>       _menu_view_refresh;
125  Widget<Gtk::CheckMenuItem>  _menu_view_toolbar;
126  Widget<Gtk::Viewport>       _project_list_viewport;
127  Widget<Gtk::Label>          _sample_rate_label;
128  Widget<Gtk::Toolbar>        _toolbar;
129  Widget<Gtk::ToolButton>     _zoom_full_but;
130  Widget<Gtk::ToolButton>     _zoom_normal_but;
131};
132
133#include "globals.hpp"
134
135#include "common.h"
136#include "Widget.hpp"
137#include <gtkmm.h>
138
139#include "common.h"
140
141#include <string.h>
142#include <cmath>
143#include <libgnomecanvasmm.h>
144#include <libglademm/xml.h>
145#include <gtk/gtkwindow.h>
146#include <boost/format.hpp>
147
148#include "project_list.hpp"
149#include "session.hpp"
150#include "globals.hpp"
151//#include "load_projects_dialog.hpp"
152#include "graph_canvas.h"
153#include "../jack_proxy.h"
154
155Patchage * g_app;
156
157#define LOG_TO_STD
158//#define LOG_TO_STATUS
159
160/* Gtk helpers (resize combo boxes) */
161
162static void
163gtkmm_get_ink_pixel_size (Glib::RefPtr<Pango::Layout> layout,
164             int& width,
165             int& height)
166{
167  Pango::Rectangle ink_rect = layout->get_ink_extents ();
168 
169  width = (ink_rect.get_width() + PANGO_SCALE / 2) / PANGO_SCALE;
170  height = (ink_rect.get_height() + PANGO_SCALE / 2) / PANGO_SCALE;
171}
172
173static void
174gtkmm_set_width_for_given_text (Gtk::Widget &w, const gchar *text,
175               gint hpadding/*, gint vpadding*/)
176 
177{
178  int old_width, old_height;
179  w.get_size_request(old_width, old_height);
180
181  int width, height;
182  w.ensure_style ();
183 
184  gtkmm_get_ink_pixel_size (w.create_pango_layout (text), width, height);
185  w.set_size_request(width + hpadding, old_height);//height + vpadding);
186}
187
188/* end Gtk helpers */
189
190
191#define INIT_WIDGET(x) x(g_xml, ((const char*)#x) + 1)
192
193Patchage::Patchage()
194  : _max_dsp_load(0.0)
195#if 0
196  , INIT_WIDGET(_about_win)
197  , INIT_WIDGET(_buffer_size_combo)
198  , INIT_WIDGET(_clear_load_but)
199  , INIT_WIDGET(_main_scrolledwin)
200  , INIT_WIDGET(_main_win)
201  , INIT_WIDGET(_main_xrun_progress)
202  , INIT_WIDGET(_main_a2j_status_label)
203  , INIT_WIDGET(_menu_file_quit)
204  , INIT_WIDGET(_menu_help_about)
205  , INIT_WIDGET(_menu_jack_start)
206  , INIT_WIDGET(_menu_jack_stop)
207  , INIT_WIDGET(_menu_a2j_start)
208  , INIT_WIDGET(_menu_a2j_stop)
209  , INIT_WIDGET(_menu_load_project)
210  , INIT_WIDGET(_menu_save_all_projects)
211  , INIT_WIDGET(_menu_close_all_projects)
212  , INIT_WIDGET(_menu_store_positions)
213  , INIT_WIDGET(_menu_view_arrange)
214  , INIT_WIDGET(_menu_view_projects)
215  , INIT_WIDGET(_menu_view_refresh)
216  , INIT_WIDGET(_menu_view_toolbar)
217  , INIT_WIDGET(_project_list_viewport)
218  , INIT_WIDGET(_sample_rate_label)
219  , INIT_WIDGET(_toolbar)
220  , INIT_WIDGET(_zoom_full_but)
221  , INIT_WIDGET(_zoom_normal_but)
222#endif
223{
224  g_app = this;
225
226  patchage_dbus_init();
227
228  graph_create(JACKDBUS_SERVICE, JACKDBUS_OBJECT, &g_jack_graph);
229  graph_canvas_create(1600 * 2, 1200 * 2, &g_jack_graph_canvas);
230  graph_canvas_attach(g_jack_graph_canvas, g_jack_graph);
231  graph_activate(g_jack_graph);
232
233  Glib::set_application_name("Patchage");
234  _about_win->property_program_name() = "Patchage";
235  _about_win->property_logo_icon_name() = "gladish";
236  gtk_window_set_default_icon_name("gladish");
237 
238  gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
239
240  _main_scrolledwin->add(*Glib::wrap(canvas_get_widget(graph_canvas_get_canvas(g_jack_graph_canvas))));
241
242//   _canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320),
243//                      static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded
244
245  _main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
246  _main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
247
248  _main_scrolledwin->signal_scroll_event().connect(
249      sigc::mem_fun(this, &Patchage::on_scroll));
250
251  _buffer_size_combo->signal_changed().connect(
252      sigc::mem_fun(this, &Patchage::buffer_size_changed));
253  _clear_load_but->signal_clicked().connect(
254      sigc::mem_fun(this, &Patchage::clear_load));
255  _zoom_normal_but->signal_clicked().connect(sigc::bind(
256      sigc::mem_fun(this, &Patchage::zoom), 1.0));
257//   _zoom_full_but->signal_clicked().connect(sigc::mem_fun(_canvas.get(), &PatchageCanvas::zoom_full));
258
259//  _menu_load_project->signal_activate().connect(sigc::mem_fun(this, &Patchage::load_project_ask));
260//  _menu_save_all_projects->signal_activate().connect(sigc::mem_fun(this, &Patchage::save_all_projects));
261//  _menu_close_all_projects->signal_activate().connect(sigc::mem_fun(this, &Patchage::close_all_projects));
262
263  _menu_file_quit->signal_activate().connect(
264      sigc::mem_fun(this, &Patchage::on_quit));
265  _menu_view_refresh->signal_activate().connect(
266      sigc::mem_fun(this, &Patchage::refresh));
267  _menu_view_arrange->signal_activate().connect(
268      sigc::mem_fun(this, &Patchage::on_arrange));
269  _menu_view_toolbar->signal_activate().connect(
270      sigc::mem_fun(this, &Patchage::on_view_toolbar));
271  _menu_view_projects->signal_toggled().connect(
272      sigc::mem_fun(this, &Patchage::on_show_projects));
273  _menu_help_about->signal_activate().connect(
274      sigc::mem_fun(this, &Patchage::on_help_about));
275
276  Glib::wrap(canvas_get_widget(graph_canvas_get_canvas(g_jack_graph_canvas)))->show();
277  _main_win->present();
278
279  _about_win->set_transient_for(*_main_win);
280
281//  _a2j = new a2j_proxy;
282
283  //info_msg(str(boost::format("a2j jack client name is '%s'") % _a2j->get_jack_client_name()));
284
285//  _session = new session();
286
287//  _project_list = new project_list(this, _session);
288//  _project_list_viewport->hide();
289
290//  _lash = new lash_proxy(_session);
291
292  //_menu_jack_start->signal_activate().connect(sigc::mem_fun(_jack, &jack_proxy::start_server));
293  //_menu_jack_stop->signal_activate().connect(sigc::mem_fun(_jack, &jack_proxy::stop_server));
294
295//  _menu_a2j_start->signal_activate().connect(sigc::mem_fun(_a2j, &a2j_proxy::start_bridge));
296//  _menu_a2j_stop->signal_activate().connect(sigc::mem_fun(_a2j, &a2j_proxy::stop_bridge));
297
298  //jack_status_changed(_jack->is_started());
299
300  connect_widgets();
301  update_state();
302
303//   _canvas->grab_focus();
304
305  // Idle callback, check if we need to refresh
306  Glib::signal_timeout().connect(
307      sigc::mem_fun(this, &Patchage::idle_callback), 100);
308}
309
310Patchage::~Patchage()
311{
312  //delete _lash;
313  //delete _project_list;
314  //delete _session;
315  //delete _a2j;
316
317  _about_win.destroy();
318  //_main_win.destroy();
319
320  patchage_dbus_uninit();
321}
322
323bool
324Patchage::idle_callback()
325{
326  update_load();
327
328  return true;
329}
330
331void
332Patchage::update_toolbar()
333{
334#if 0
335  bool started;
336
337  started = _jack->is_started();
338
339  _buffer_size_combo->set_sensitive(started);
340
341  if (started)
342  {
343    _buffer_size_combo->set_active((int)log2f(_jack->buffer_size()) - 5);
344  }
345#endif
346}
347
348void
349Patchage::update_load()
350{
351#if 0
352  if (!_jack->is_started())
353  {
354    _main_xrun_progress->set_text("JACK stopped");
355    return;
356  }
357
358  char tmp_buf[8];
359  snprintf(tmp_buf, 8, "%zd", _jack->xruns());
360
361  _main_xrun_progress->set_text(std::string(tmp_buf) + " Dropouts");
362
363  float load = _jack->get_dsp_load();
364
365  load /= 100.0;                // dbus returns it in percents, we use 0..1
366
367  if (load > _max_dsp_load)
368  {
369    _max_dsp_load = load;
370    _main_xrun_progress->set_fraction(load);
371  }
372#endif
373}
374
375
376void
377Patchage::zoom(double z)
378{
379//   _canvas->set_zoom(z);
380}
381
382
383void
384Patchage::refresh()
385{
386//   assert(_canvas);
387
388//   _canvas->destroy();
389
390//   if (_jack)
391//     _jack->refresh();
392
393//   for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
394//     (*i)->resize();
395//   }
396}
397
398void
399Patchage::clear_load()
400{
401#if 0
402  _main_xrun_progress->set_fraction(0.0);
403  _jack->reset_xruns();
404  _max_dsp_load = 0.0;
405#endif
406}
407
408void
409Patchage::update_state()
410{
411//   for (ItemList::iterator i = _canvas->items().begin(); i != _canvas->items().end(); ++i) {
412//     shared_ptr<Module> module = dynamic_pointer_cast<Module>(*i);
413//     if (module)
414//       module->load_location();
415//   }
416}
417
418
419/** Update the sensitivity status of menus to reflect the present.
420 *
421 * (eg. disable "Connect to Jack" when Patchage is already connected to Jack)
422 */
423void
424Patchage::connect_widgets()
425{
426  //_jack->signal_started.connect(sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), true));
427  //_jack->signal_stopped.connect(sigc::bind(sigc::mem_fun(this, &Patchage::jack_status_changed), false));
428}
429
430void
431Patchage::jack_status_changed(
432  bool started)
433{
434  update_toolbar();
435
436  _menu_jack_start->set_sensitive(!started);
437  _menu_jack_stop->set_sensitive(started);
438  _clear_load_but->set_sensitive(started);
439  if (!started)
440  {
441    _main_xrun_progress->set_fraction(0.0);
442  }
443}
444
445void
446Patchage::on_arrange()
447{
448//   assert(_canvas);
449 
450//   _canvas->arrange();
451}
452
453 
454void
455Patchage::on_help_about()
456{
457  _about_win->run();
458  _about_win->hide();
459}
460
461
462void
463Patchage::on_quit()
464{
465  _main_win->hide();
466}
467
468void
469Patchage::on_show_projects()
470{
471  if (_menu_view_projects->get_active())
472    _project_list_viewport->show();
473  else
474    _project_list_viewport->hide();
475}
476
477void
478Patchage::on_view_toolbar()
479{
480  if (_menu_view_toolbar->get_active())
481    _toolbar->show();
482  else
483    _toolbar->hide();
484}
485
486 
487bool
488Patchage::on_scroll(GdkEventScroll* ev)
489{
490  lash_debug("ON SCROLL");
491  return false;
492}
493
494
495void
496Patchage::buffer_size_changed()
497{
498#if 0
499  const int selected = _buffer_size_combo->get_active_row_number();
500
501  if (selected == -1)
502  {
503    update_toolbar();
504  }
505  else
506  {
507    uint32_t buffer_size = 1 << (selected+5);
508 
509    // this check is temporal workaround for jack bug
510    // we skip setting buffer size if it same as acutal one
511    // proper place for such check is in jack
512    if (_jack->buffer_size() != buffer_size)
513    {
514      if (!_jack->set_buffer_size(buffer_size))
515      {
516        update_toolbar(); // reset combo box to actual value
517      }
518    }
519  }
520#endif
521}
522
523void
524Patchage::set_studio_availability(
525  bool available)
526{
527  if (available)
528  {
529    _main_win->set_title("Active Studio - LADI Session Handler");
530  }
531  else
532  {
533    _main_win->set_title("LADI Session Handler");
534  }
535  //_project_list->set_lash_availability(available);
536  _menu_view_projects->set_active(available);
537}
538
539#if 0
540void
541Patchage::set_a2j_status(
542  unsigned int status)
543{
544  const char * status_text;
545
546  switch (status)
547  {
548  case A2J_STATUS_NO_RESPONSE:
549    status_text = "A2J N/A";
550    _menu_a2j_start->set_sensitive(false);
551    _menu_a2j_stop->set_sensitive(false);
552    break;
553  case A2J_STATUS_BRIDGE_STOPPED:
554    status_text = "A2J bridge stopped";
555    _menu_a2j_start->set_sensitive(true);
556    _menu_a2j_stop->set_sensitive(false);
557    break;
558  case A2J_STATUS_BRIDGE_STARTED:
559    status_text = "A2J bridge started";
560    _menu_a2j_start->set_sensitive(false);
561    _menu_a2j_stop->set_sensitive(true);
562    break;
563  default:
564    error_msg(str(boost::format("Unknown A2J status %u") % status));
565    status_text = "Unknown A2J status";
566    _menu_a2j_start->set_sensitive(true);
567    _menu_a2j_stop->set_sensitive(true);
568    break;
569  }
570
571  _main_a2j_status_label->set_text(status_text);
572}
573
574void
575Patchage::load_project_ask()
576{
577  std::list<lash_project_info> projects;
578
579  _lash->get_available_projects(projects);
580  run_load_project_dialog(projects);
581}
582
583void
584Patchage::load_project(
585  const std::string& project_name)
586{
587  _lash->load_project(project_name);
588}
589
590void
591Patchage::save_all_projects()
592{
593  _lash->save_all_projects();
594}
595
596void
597Patchage::save_project(
598  const std::string& project_name)
599{
600  _lash->save_project(project_name);
601}
602
603void
604Patchage::close_project(
605  const std::string& project_name)
606{
607  _lash->close_project(project_name);
608}
609
610void
611Patchage::close_all_projects()
612{
613  _lash->close_all_projects();
614}
615
616void
617Patchage::on_port_added(
618  const char * jack_client_name,
619  const char * jack_port_name,
620  PortType port_type,
621  bool is_input,
622  bool is_terminal)
623{
624  bool is_a2j_mapped;
625  std::string canvas_client_name;
626  std::string canvas_port_name;
627  uint32_t alsa_client_id;
628  boost::shared_ptr<PatchageModule> module;
629
630  is_a2j_mapped = strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0;
631  if (is_a2j_mapped)
632  {
633    if (!_a2j->map_jack_port(jack_port_name, canvas_client_name, canvas_port_name, alsa_client_id))
634    {
635      return;
636    }
637
638    canvas_port_name = str(boost::format(canvas_port_name + " [a2j:%u]") % alsa_client_id);
639  }
640  else
641  {
642    canvas_client_name = jack_client_name;
643    canvas_port_name = jack_port_name;
644  }
645
646  ModuleType module_type = InputOutput;
647  if (_state_manager->get_module_split(canvas_client_name, is_terminal && !is_a2j_mapped)) {
648    if (is_input) {
649      module_type = Input;
650    } else {
651      module_type = Output;
652    }
653  }
654
655  module = _canvas->find_module(canvas_client_name, module_type);
656  if (!module) {
657    module = boost::shared_ptr<PatchageModule>(new PatchageModule(this, canvas_client_name, module_type));
658    module->load_location();
659    _canvas->add_item(module);
660  }
661
662  if (module->get_port(canvas_port_name)) {
663    return;
664  }
665
666  boost::shared_ptr<PatchagePort> port = boost::shared_ptr<PatchagePort>(
667    new PatchagePort(
668      module,
669      canvas_port_name,
670      is_input,
671      _state_manager->get_port_color(port_type)));
672
673  port->type = port_type;
674  port->is_a2j_mapped = is_a2j_mapped;
675  if (is_a2j_mapped)
676  {
677    port->a2j_jack_port_name = jack_port_name;
678  }
679
680  module->add_port(port);
681
682  module->resize();
683}
684
685boost::shared_ptr<PatchagePort>
686Patchage::lookup_port(
687  const char * jack_client_name,
688  const char * jack_port_name)
689{
690  if (strcmp(_a2j->get_jack_client_name(), jack_client_name) == 0)
691  {
692    return _canvas->lookup_port_by_a2j_jack_port_name(jack_port_name);
693  }
694
695  return _canvas->get_port(jack_client_name, jack_port_name);
696}
697
698void
699Patchage::on_port_removed(
700  const char * jack_client_name,
701  const char * jack_port_name)
702{
703  boost::shared_ptr<PatchagePort> port = lookup_port(jack_client_name, jack_port_name);
704  if (!port) {
705    error_msg(str(boost::format("Unable to remove unknown port '%s':'%s'") % jack_client_name % jack_port_name));
706    return;
707  }
708
709  boost::shared_ptr<PatchageModule> module = dynamic_pointer_cast<PatchageModule>(port->module().lock());
710
711  module->remove_port(port);
712  port.reset();
713     
714  // No empty modules (for now)
715  if (module->num_ports() == 0) {
716    _canvas->remove_item(module);
717    module.reset();
718  } else {
719    module->resize();
720  }
721}
722
723void
724Patchage::on_ports_connected(
725  const char * jack_client1_name,
726  const char * jack_port1_name,
727  const char * jack_client2_name,
728  const char * jack_port2_name)
729{
730  boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
731  if (!port1) {
732    error_msg((std::string)"Unable to connect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
733    return;
734  }
735
736  boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
737  if (!port2) {
738    error_msg((std::string)"Unable to connect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
739    return;
740  }
741
742  _canvas->add_connection(port1, port2, port1->color() + 0x22222200);
743}
744
745void
746Patchage::on_ports_disconnected(
747  const char * jack_client1_name,
748  const char * jack_port1_name,
749  const char * jack_client2_name,
750  const char * jack_port2_name)
751{
752  boost::shared_ptr<PatchagePort> port1 = lookup_port(jack_client1_name, jack_port1_name);
753  if (!port1) {
754    error_msg((std::string)"Unable to disconnect unknown port '" + jack_port1_name + "' of client '" + jack_client1_name + "'");
755    return;
756  }
757
758  boost::shared_ptr<PatchagePort> port2 = lookup_port(jack_client2_name, jack_port2_name);
759  if (!port2) {
760    error_msg((std::string)"Unable to disconnect unknown port '" + jack_port2_name + "' of client '" + jack_client2_name + "'");
761    return;
762  }
763
764  _canvas->remove_connection(port1, port2);
765}
766
767static
768bool
769port_type_match(
770  boost::shared_ptr<PatchagePort> port1,
771  boost::shared_ptr<PatchagePort> port2)
772{
773  return port1->type == port2->type;
774}
775
776void
777Patchage::get_port_jack_names(
778  boost::shared_ptr<PatchagePort> port,
779  std::string& jack_client_name,
780  std::string& jack_port_name)
781{
782  if (port->is_a2j_mapped)
783  {
784    jack_client_name = _a2j->get_jack_client_name();
785    jack_port_name = port->a2j_jack_port_name;
786  }
787  else
788  {
789    jack_client_name = port->module().lock()->name();
790    jack_port_name = port->name();
791  }
792}
793
794void
795Patchage::connect(
796  boost::shared_ptr<PatchagePort> port1,
797  boost::shared_ptr<PatchagePort> port2)
798{
799  std::string jack_client1_name;
800  std::string jack_port1_name;
801  std::string jack_client2_name;
802  std::string jack_port2_name;
803
804  if (port_type_match(port1, port2))
805  {
806    get_port_jack_names(port1, jack_client1_name, jack_port1_name);
807    get_port_jack_names(port2, jack_client2_name, jack_port2_name);
808
809    _jack->connect(
810      jack_client1_name.c_str(),
811      jack_port1_name.c_str(),
812      jack_client2_name.c_str(),
813      jack_port2_name.c_str());
814  }
815  else
816  {
817    status_msg("ERROR: Attempt to connect ports with mismatched types");
818  }
819}
820
821void
822Patchage::disconnect(
823  boost::shared_ptr<PatchagePort> port1,
824  boost::shared_ptr<PatchagePort> port2)
825{
826  std::string jack_client1_name;
827  std::string jack_port1_name;
828  std::string jack_client2_name;
829  std::string jack_port2_name;
830
831  if (port_type_match(port1, port2))
832  {
833    get_port_jack_names(port1, jack_client1_name, jack_port1_name);
834    get_port_jack_names(port2, jack_client2_name, jack_port2_name);
835
836    _jack->disconnect(
837      jack_client1_name.c_str(),
838      jack_port1_name.c_str(),
839      jack_client2_name.c_str(),
840      jack_port2_name.c_str());
841  }
842  else
843  {
844    status_msg("ERROR: Attempt to disconnect ports with mismatched types");
845  }
846}
847
848bool
849Patchage::is_canvas_empty()
850{
851  return _canvas->items().empty();
852}
853#endif
854#endif
855
856GtkScrolledWindow * g_main_scrolledwin;
857
858struct view
859{
860  char * name;
861  graph_canvas_handle graph_canvas;
862  graph_handle graph;
863  GtkWidget * canvas_widget;
864};
865
866struct view * create_view(const char * name, const char * service, const char * object)
867{
868  struct view * view_ptr;
869
870  view_ptr = malloc(sizeof(struct view));
871  if (view_ptr == NULL)
872  {
873    lash_error("malloc() failed for struct view");
874    goto fail;
875  }
876
877  view_ptr->name = strdup(name);
878  if (view_ptr->name == NULL)
879  {
880    lash_error("strdup() failed for \"%s\"", name);
881    goto free_view;
882  }
883
884  if (!graph_create(service, object, &view_ptr->graph))
885  {
886    goto free_name;
887  }
888
889  if (!graph_canvas_create(1600 * 2, 1200 * 2, &view_ptr->graph_canvas))
890  {
891    goto destroy_graph;
892  }
893
894  if (!graph_canvas_attach(view_ptr->graph_canvas, view_ptr->graph))
895  {
896    goto destroy_graph_canvas;
897  }
898
899  if (!graph_activate(view_ptr->graph))
900  {
901    goto detach_graph_canvas;
902  }
903
904  view_ptr->canvas_widget = canvas_get_widget(graph_canvas_get_canvas(view_ptr->graph_canvas));
905
906  gtk_widget_show(view_ptr->canvas_widget);
907
908  return view_ptr;
909
910detach_graph_canvas:
911  graph_canvas_detach(view_ptr->graph_canvas);
912destroy_graph_canvas:
913  graph_canvas_destroy(view_ptr->graph_canvas);
914destroy_graph:
915  graph_destroy(view_ptr->graph);
916free_name:
917  free(view_ptr->name);
918free_view:
919  free(view_ptr);
920fail:
921  return NULL;
922}
923
924void destroy_view(struct view * view_ptr)
925{
926  graph_canvas_detach(view_ptr->graph_canvas);
927  graph_canvas_destroy(view_ptr->graph_canvas);
928  graph_destroy(view_ptr->graph);
929  free(view_ptr->name);
930  free(view_ptr);
931}
932
933void attach_view(struct view * view_ptr)
934{
935  GtkWidget * child;
936
937  child = gtk_bin_get_child(GTK_BIN(g_main_scrolledwin));
938  if (child != NULL)
939  {
940    gtk_container_remove(GTK_CONTAINER(g_main_scrolledwin), child);
941  }
942
943  gtk_container_add(GTK_CONTAINER(g_main_scrolledwin), view_ptr->canvas_widget);
944
945  //_canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320), static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded
946  //_main_scrolledwin->property_hadjustment().get_value()->set_step_increment(10);
947  //_main_scrolledwin->property_vadjustment().get_value()->set_step_increment(10);
948}
949
950void detach_view(struct view * view_ptr)
951{
952  GtkWidget * child;
953
954  child = gtk_bin_get_child(GTK_BIN(g_main_scrolledwin));
955  if (child == view_ptr->canvas_widget)
956  {
957    gtk_container_remove(GTK_CONTAINER(g_main_scrolledwin), view_ptr->canvas_widget);
958  }
959}
960
961struct view * g_jack_view;
962struct view * g_studio_view;
963
964void control_proxy_on_studio_appeared(void)
965{
966  g_studio_view = create_view("Studio", SERVICE_NAME, STUDIO_OBJECT_PATH);
967  attach_view(g_studio_view);
968  g_jack_view = create_view("Raw JACK", JACKDBUS_SERVICE_NAME, JACKDBUS_OBJECT_PATH);
969  attach_view(g_jack_view);
970}
971
972void control_proxy_on_studio_disappeared(void)
973{
974  detach_view(g_jack_view);
975  destroy_view(g_jack_view);
976  detach_view(g_studio_view);
977  destroy_view(g_studio_view);
978}
979
980int main(int argc, char** argv)
981{
982  GtkWidget * main_win;
983
984  gtk_init(&argc, &argv);
985
986  if (!canvas_init())
987  {
988    lash_error("Canvas initialization failed.");
989    return 1;
990  }
991
992  if (!init_glade())
993  {
994    return 1;
995  }
996
997  /* Obtain widgets that we need */
998  main_win = get_glade_widget("main_win");
999  g_main_scrolledwin = GTK_SCROLLED_WINDOW(get_glade_widget("main_scrolledwin"));
1000
1001  patchage_dbus_init();
1002
1003  if (!control_proxy_init())
1004  {
1005    return 1;
1006  }
1007
1008  //gtkmm_set_width_for_given_text(*_buffer_size_combo, "4096 frames", 40);
1009
1010  g_signal_connect(G_OBJECT(main_win), "destroy", G_CALLBACK(gtk_main_quit), NULL);
1011  g_signal_connect(G_OBJECT(get_glade_widget("menu_file_quit")), "activate", G_CALLBACK(gtk_main_quit), NULL);
1012
1013  gtk_widget_show(main_win);
1014
1015  //_about_win->set_transient_for(*_main_win);
1016
1017  gtk_main();
1018
1019  control_proxy_uninit();
1020  uninit_glade();
1021
1022  return 0;
1023}
Note: See TracBrowser for help on using the browser.