diff options
-rw-r--r-- | aclocal.m4 | 3 | ||||
-rw-r--r-- | src/AlsaDriver.cpp | 163 | ||||
-rw-r--r-- | src/AlsaDriver.h | 16 | ||||
-rw-r--r-- | src/Driver.h | 26 | ||||
-rw-r--r-- | src/JackDriver.cpp | 266 | ||||
-rw-r--r-- | src/JackDriver.h | 31 | ||||
-rw-r--r-- | src/LashDriver.cpp | 20 | ||||
-rw-r--r-- | src/LashDriver.h | 10 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/Patchage.cpp | 231 | ||||
-rw-r--r-- | src/Patchage.h | 24 | ||||
-rw-r--r-- | src/PatchageFlowCanvas.cpp | 63 | ||||
-rw-r--r-- | src/PatchageFlowCanvas.h | 8 | ||||
-rw-r--r-- | src/PatchageModule.h | 12 | ||||
-rw-r--r-- | src/PatchagePort.h | 11 | ||||
-rw-r--r-- | src/StateManager.cpp | 4 | ||||
-rw-r--r-- | src/StateManager.h | 4 | ||||
-rw-r--r-- | src/main.cpp | 10 | ||||
-rw-r--r-- | src/patchage.glade | 522 |
19 files changed, 813 insertions, 612 deletions
@@ -149,7 +149,8 @@ installed software in a non-standard prefix. _PKG_TEXT ])], - [$4]) + [AC_MSG_RESULT([no]) + $4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 909a710..43ee297 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -49,25 +49,24 @@ AlsaDriver::~AlsaDriver() * @a launch_daemon is ignored, as ALSA has no daemon to launch/connect to. */ void -AlsaDriver::attach(bool launch_daemon) +AlsaDriver::attach(bool /*launch_daemon*/) { - cout << "Connecting to Alsa... "; - cout.flush(); - int ret = snd_seq_open(&m_seq, "default", SND_SEQ_OPEN_DUPLEX, SND_SEQ_NONBLOCK); if (ret) { - cout << "Failed" << endl; + m_app->status_message("[ALSA] Unable to attach"); m_seq = NULL; } else { - cout << "Connected" << endl; + m_app->status_message("[ALSA] Attached"); snd_seq_set_client_name(m_seq, "Patchage"); ret = pthread_create(&m_refresh_thread, NULL, &AlsaDriver::refresh_main, this); if (ret) cerr << "Couldn't start refresh thread" << endl; + + signal_attached.emit(); } } @@ -80,7 +79,8 @@ AlsaDriver::detach() pthread_join(m_refresh_thread, NULL); snd_seq_close(m_seq); m_seq = NULL; - cout << "Disconnected from Alsa" << endl; + signal_detached.emit(); + m_app->status_message("[ALSA] Detached"); } } @@ -102,6 +102,18 @@ AlsaDriver::refresh() } +boost::shared_ptr<PatchagePort> +AlsaDriver::create_port(boost::shared_ptr<PatchageModule> parent, + const string& name, bool is_input, snd_seq_addr_t addr) +{ + boost::shared_ptr<PatchagePort> ret( + new PatchagePort(parent, ALSA_MIDI, name, is_input, + m_app->state_manager()->get_port_color(ALSA_MIDI))); + ret->alsa_addr(addr); + return ret; +} + + /** Refresh all Alsa Midi ports. */ void @@ -159,7 +171,7 @@ AlsaDriver::refresh_ports() is_application = (type & SND_SEQ_PORT_TYPE_APPLICATION); port_name = snd_seq_port_info_get_name(pinfo); - PatchageModule* m = NULL; + boost::shared_ptr<PatchageModule> m; //cout << client_name << " : " << port_name << " is_application = " << is_application // << " is_duplex = " << is_duplex << endl; @@ -168,22 +180,23 @@ AlsaDriver::refresh_ports() // Application input/output ports go on the same module if (!split) { - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); + if (!m) { + m = boost::shared_ptr<PatchageModule>(new PatchageModule(m_app, client_name, InputOutput)); m->load_location(); m->store_location(); - m->show(); + m_app->canvas()->add_module(m); } - if (!is_duplex) { - m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr); - } else { - m->add_patchage_port(port_name, true, ALSA_MIDI, addr); - m->add_patchage_port(port_name, false, ALSA_MIDI, addr); + if (!m->get_port(port_name)) { + if (!is_duplex) { + m->add_port(create_port(m, port_name, is_input, addr)); + } else { + m->add_port(create_port(m, port_name, true, addr)); + m->add_port(create_port(m, port_name, false, addr)); + } } } else { // non-application input/output ports (hw interface, etc) go on separate modules - PatchageModule* m = NULL; ModuleType type = InputOutput; // The 'application' hint isn't always set by clients, so this bit @@ -194,46 +207,61 @@ AlsaDriver::refresh_ports() else type = Output; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr<PatchageModule>( + new PatchageModule(m_app, client_name, type)); m->load_location(); m->store_location(); + m_app->canvas()->add_module(m); } - m->add_patchage_port(port_name, is_input, ALSA_MIDI, addr); + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, is_input, addr)); } else { // two ports to add type = Input; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr<PatchageModule>( + new PatchageModule(m_app, client_name, type)); m->load_location(); m->store_location(); } - m->add_patchage_port(port_name, true, ALSA_MIDI, addr); + + assert(m); + + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, true, addr)); type = Output; // See if an InputOutput module exists (maybe with Jack ports on it) - m = (PatchageModule*)m_canvas->find_module(client_name, InputOutput); + m = m_canvas->find_module(client_name, InputOutput); - if (m == NULL) - m = (PatchageModule*)m_canvas->find_module(client_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client_name, type); + if (!m) + m = m_canvas->find_module(client_name, type); + + if (!m) { + m = boost::shared_ptr<PatchageModule>( + new PatchageModule(m_app, client_name, type)); + m->load_location(); m->store_location(); } - m->add_patchage_port(port_name, false, ALSA_MIDI, addr); + if (!m->get_port(port_name)) + m->add_port(create_port(m, port_name, false, addr)); } - m->show(); + m->resize(); + m_app->canvas()->add_module(m); } } } @@ -248,16 +276,18 @@ AlsaDriver::refresh_connections() assert(is_attached()); assert(m_seq); - PatchageModule* m = NULL; - PatchagePort* p = NULL; + boost::shared_ptr<PatchageModule> m; + boost::shared_ptr<PatchagePort> p; for (ModuleMap::iterator i = m_canvas->modules().begin(); i != m_canvas->modules().end(); ++i) { - m = (PatchageModule*)((*i).second); - for (PortList::iterator j = m->ports().begin(); j != m->ports().end(); ++j) { - p = (PatchagePort*)(*j); - if (p->type() == ALSA_MIDI) - add_connections(p); + m = boost::dynamic_pointer_cast<PatchageModule>((*i).second); + if (m) { + for (PortVector::const_iterator j = m->ports().begin(); j != m->ports().end(); ++j) { + p = boost::dynamic_pointer_cast<PatchagePort>(*j); + if (p->type() == ALSA_MIDI) + add_connections(p); + } } } } @@ -266,13 +296,13 @@ AlsaDriver::refresh_connections() /** Add all connections for the given port. */ void -AlsaDriver::add_connections(PatchagePort* port) +AlsaDriver::add_connections(boost::shared_ptr<PatchagePort> port) { assert(is_attached()); assert(m_seq); - const snd_seq_addr_t* addr = port->alsa_addr(); - PatchagePort* connected_port = NULL; + const snd_seq_addr_t* addr = port->alsa_addr(); + boost::shared_ptr<PatchagePort> connected_port; // Fix a problem with duplex->duplex connections (would show up twice) // No sense doing them all twice anyway.. @@ -287,10 +317,15 @@ AlsaDriver::add_connections(PatchagePort* port) while(!snd_seq_query_port_subscribers(m_seq, subsinfo)) { const snd_seq_addr_t* connected_addr = snd_seq_query_subscribe_get_addr(subsinfo); - connected_port = m_canvas->find_port(connected_addr, !port->is_input()); - - if (connected_port != NULL) { - m_canvas->add_connection(port, connected_port); + connected_port = m_canvas->find_port(connected_addr); + + if (connected_port) { + boost::shared_ptr<Connection> existing = m_canvas->get_connection(port, connected_port); + if (existing) { + existing->set_flagged(false); + } else { + m_canvas->add_connection(port, connected_port); + } } snd_seq_query_subscribe_set_index(subsinfo, snd_seq_query_subscribe_get_index(subsinfo) + 1); @@ -304,12 +339,12 @@ AlsaDriver::add_connections(PatchagePort* port) * \return Whether connection succeeded. */ bool -AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +AlsaDriver::connect(boost::shared_ptr<PatchagePort> src_port, boost::shared_ptr<PatchagePort> dst_port) { const snd_seq_addr_t* src = src_port->alsa_addr(); const snd_seq_addr_t* dst = dst_port->alsa_addr(); - bool result = false; + bool result = true; if (src && dst) { snd_seq_port_subscribe_t* subs; @@ -332,6 +367,13 @@ AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons result = false; } } + + if (result) + m_app->status_message(string("[ALSA] Connected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[ALSA] Unable to connect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } @@ -342,12 +384,12 @@ AlsaDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons * \return Whether disconnection succeeded. */ bool -AlsaDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +AlsaDriver::disconnect(boost::shared_ptr<PatchagePort> src_port, boost::shared_ptr<PatchagePort> dst_port) { const snd_seq_addr_t* src = src_port->alsa_addr(); const snd_seq_addr_t* dst = dst_port->alsa_addr(); - bool result = false; + bool result = true; snd_seq_port_subscribe_t* subs; snd_seq_port_subscribe_malloc(&subs); @@ -368,6 +410,13 @@ AlsaDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* c cerr << "Alsa unsubscription failed: " << snd_strerror(ret) << endl; result = false; } + + if (result) + m_app->status_message(string("[ALSA] Disconnected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[ALSA] Unable to disconnect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } diff --git a/src/AlsaDriver.h b/src/AlsaDriver.h index d6e910f..27ddee9 100644 --- a/src/AlsaDriver.h +++ b/src/AlsaDriver.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -45,8 +45,11 @@ public: void refresh(); - bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port); + bool connect(boost::shared_ptr<PatchagePort> src_port, + boost::shared_ptr<PatchagePort> dst_port); + + bool disconnect(boost::shared_ptr<PatchagePort> src_port, + boost::shared_ptr<PatchagePort> dst_port); PatchageFlowCanvas* canvas() { return m_canvas; } @@ -54,12 +57,15 @@ private: void refresh_ports(); void refresh_connections(); - void add_connections(PatchagePort* port); + void add_connections(boost::shared_ptr<PatchagePort> port); bool create_refresh_port(); static void* refresh_main(void* me); void m_refresh_main(); + boost::shared_ptr<PatchagePort> create_port(boost::shared_ptr<PatchageModule> parent, + const string& name, bool is_input, snd_seq_addr_t addr); + Patchage* m_app; PatchageFlowCanvas* m_canvas; diff --git a/src/Driver.h b/src/Driver.h index 1b7ad80..1945286 100644 --- a/src/Driver.h +++ b/src/Driver.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -17,6 +17,9 @@ #ifndef DRIVER_H #define DRIVER_H +#include <boost/shared_ptr.hpp> +#include <sigc++/sigc++.h> + class PatchagePort; /** Trival driver base class */ @@ -30,19 +33,20 @@ public: virtual void refresh() = 0; - virtual bool connect(const PatchagePort* src_port, - const PatchagePort* dst_port) - { return false; } + virtual bool connect(boost::shared_ptr<PatchagePort> src_port, + boost::shared_ptr<PatchagePort> dst_port) = 0; - virtual bool disconnect(const PatchagePort* src_port, - const PatchagePort* dst_port) - { return false; } + virtual bool disconnect(boost::shared_ptr<PatchagePort> src_port, + boost::shared_ptr<PatchagePort> dst_port) = 0; - /** Returns whether or not a refresh is required. */ - bool is_dirty() const { return m_is_dirty; } + /** Returns whether or not a refresh is required (pending). */ + inline bool is_dirty() const { return m_is_dirty; } /** Clear 'dirty' status after a refresh. */ - void undirty() { m_is_dirty = false; } + inline void undirty() { m_is_dirty = false; } + + sigc::signal<void> signal_attached; + sigc::signal<void> signal_detached; protected: Driver() : m_is_dirty(false) {} diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp index c40e589..8147678 100644 --- a/src/JackDriver.cpp +++ b/src/JackDriver.cpp @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -24,7 +24,7 @@ #include "Patchage.h" #include "PatchageModule.h" -using std::cerr; using std::endl; using std::cout; +using std::cerr; using std::endl; using std::string; using namespace LibFlowCanvas; @@ -49,30 +49,25 @@ JackDriver::~JackDriver() void JackDriver::attach(bool launch_daemon) { - cout << "Connecting to Jack... "; - cout.flush(); - - if (m_client != NULL) { - cout << "already connected. " << endl; + // Already connected + if (m_client) return; - } jack_options_t options = (!launch_daemon) ? JackNoStartServer : JackNullOption; m_client = jack_client_open("Patchage", options, NULL); if (m_client == NULL) { - cout << "Failed" << endl; + m_app->status_message("[JACK] Unable to attach"); } else { + jack_on_shutdown(m_client, jack_shutdown_cb, this); jack_set_port_registration_callback(m_client, jack_port_registration_cb, this); jack_set_graph_order_callback(m_client, jack_graph_order_cb, this); - jack_on_shutdown(m_client, jack_shutdown_cb, this); - jack_activate(m_client); - - cout << "Connected" << endl; - - m_canvas->destroy(); - m_is_dirty = true; + + jack_activate(m_client); + + signal_attached.emit(); + m_app->status_message("[JACK] Attached"); } } @@ -84,33 +79,88 @@ JackDriver::detach() jack_deactivate(m_client); jack_client_close(m_client); m_client = NULL; - cout << "Disconnected from Jack" << endl; + signal_detached.emit(); + destroy_all_ports(); + m_app->status_message("[JACK] Detached"); + } +} + + +/** Destroy all JACK (canvas) ports. + */ +void +JackDriver::destroy_all_ports() +{ + ModuleMap modules = m_canvas->modules(); // copy + for (ModuleMap::iterator m = modules.begin(); m != modules.end(); ++m) { + PortVector ports = m->second->ports(); // copy + for (PortVector::iterator p = ports.begin(); p != ports.end(); ++p) { + boost::shared_ptr<PatchagePort> port = boost::dynamic_pointer_cast<PatchagePort>(*p); + if (port && port->type() == JACK_AUDIO || port->type() == JACK_MIDI) { + port.reset(); + } + } + + if (m->second->ports().empty()) + m->second.reset(); } } +boost::shared_ptr<PatchagePort> +JackDriver::create_port(boost::shared_ptr<PatchageModule> parent, jack_port_t* port) +{ + const char* const type_str = jack_port_type(port); + PortType port_type; + if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) { + port_type = JACK_MIDI; + } else if (!strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) { + port_type = JACK_AUDIO; + } else { + cerr << "WARNING: " << jack_port_name(port) << " has unknown type \'" << type_str << "\'" << endl; + return boost::shared_ptr<PatchagePort>(); + } + + boost::shared_ptr<PatchagePort> ret( + new PatchagePort(parent, port_type, jack_port_short_name(port), + (jack_port_flags(port) & JackPortIsInput), + m_app->state_manager()->get_port_color(port_type))); + + return ret; +} + + /** Refresh all Jack audio ports/connections. * To be called from GTK thread only. */ void JackDriver::refresh() { - if (m_client == NULL) + m_mutex.lock(); + + if (m_client == NULL) { + // Shutdown + if (m_is_dirty) { + signal_detached.emit(); + destroy_all_ports(); + } + m_is_dirty = false; + m_mutex.unlock(); return; - + } + const char** ports; jack_port_t* port; - + ports = jack_get_ports(m_client, NULL, NULL, 0); // get all existing ports string client1_name; string port1_name; string client2_name; string port2_name; - PatchageModule* m = NULL; - + // Add all ports - if (ports != NULL) + if (ports) for (int i=0; ports[i]; ++i) { port = jack_port_by_name(m_client, ports[i]); client1_name = ports[i]; @@ -118,9 +168,9 @@ JackDriver::refresh() ModuleType type = InputOutput; //if (m_app->state_manager()->get_module_split(client1_name) - // || jack_port_flags(port) & JackPortIsTerminal) { + // || jack_port_flags(port) & JackPortIsTerminal) if (m_app->state_manager()->get_module_split(client1_name, - (jack_port_flags(port) & JackPortIsTerminal))) { + (jack_port_flags(port) & JackPortIsTerminal))) { if (jack_port_flags(port) & JackPortIsInput) { type = Input; } else { @@ -128,56 +178,84 @@ JackDriver::refresh() } } - m = (PatchageModule*)m_canvas->find_module(client1_name, type); + boost::shared_ptr<PatchageModule> m = m_canvas->find_module(client1_name, type); - if (m == NULL) { - m = new PatchageModule(m_app, client1_name, type); + if (!m) { + m = boost::shared_ptr<PatchageModule>(new PatchageModule(m_app, client1_name, type)); m->load_location(); m->store_location(); - m->show(); + m_app->canvas()->add_module(m); } - + // FIXME: leak? jack docs don't say const char* const type_str = jack_port_type(port); - PortType port_type = JACK_AUDIO; - if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) + PortType port_type; + if (!strcmp(type_str, JACK_DEFAULT_MIDI_TYPE)) { port_type = JACK_MIDI; - else if (strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) - throw "Unknown JACK port type?"; + } else if (!strcmp(type_str, JACK_DEFAULT_AUDIO_TYPE)) { + port_type = JACK_AUDIO; + } else { + cerr << "WARNING: " << ports[i] << " has unknown type \'" << type_str << "\'" << endl; + continue; + } - m->add_patchage_port(jack_port_short_name(port), - (jack_port_flags(port) & JackPortIsInput), - port_type); + if (!m->get_port(jack_port_short_name(port))) { + m->add_port(create_port(m, port)); + } + + m->resize(); } + + // Remove any since-removed ports + for (list<string>::iterator i = m_removed_ports.begin(); i != m_removed_ports.end(); ++i) { + const string module_name = (*i).substr(0, i->find(":")); + const string port_name = (*i).substr(i->find(":")+1); + + for (ModuleMap::iterator m = m_canvas->modules().begin(); m != m_canvas->modules().end(); ++m) { + if (m->second->name() == module_name) + m->second->remove_port(port_name); + } + } + + // Add all connections - if (ports != NULL) { - for (int i=0; ports[i]; ++i) { - port = jack_port_by_name(m_client, ports[i]); - const char** connected_ports = jack_port_get_all_connections(m_client, port); - - if (connected_ports != NULL) + if (ports) + for (int i=0; ports[i]; ++i) { + port = jack_port_by_name(m_client, ports[i]); + const char** connected_ports = jack_port_get_all_connections(m_client, port); + + if (connected_ports) { for (int j=0; connected_ports[j]; ++j) { client1_name = ports[i]; port1_name = client1_name.substr(client1_name.find(':')+1); client1_name = client1_name.substr(0, client1_name.find(':')); - + client2_name = connected_ports[j]; port2_name = client2_name.substr(client2_name.find(':')+1); client2_name = client2_name.substr(0, client2_name.find(':')); - - Port* const port1 = m_canvas->get_port(client1_name, port1_name); - Port* const port2 = m_canvas->get_port(client2_name, port2_name); - - if (port1 && port2) - m_canvas->add_connection(port1, port2); + + boost::shared_ptr<Port> port1 = m_canvas->get_port(client1_name, port1_name); + boost::shared_ptr<Port> port2 = m_canvas->get_port(client2_name, port2_name); + + if (port1 && port2) { + boost::shared_ptr<Connection> existing = m_canvas->get_connection(port1, port2); + if (existing) { + existing->set_flagged(false); + } else { + m_canvas->add_connection(port1, port2); + } + } } + free(connected_ports); - } - free(ports); + } } + free(ports); undirty(); + + m_mutex.unlock(); } @@ -186,22 +264,19 @@ JackDriver::refresh() * \return Whether connection succeeded. */ bool -JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +JackDriver::connect(boost::shared_ptr<PatchagePort> src_port, boost::shared_ptr<PatchagePort> dst_port) { if (m_client == NULL) return false; int result = jack_connect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str()); - string msg; - - if (result == 0) { - msg = "Successfully connected jack ports"; - } else { - msg = "Unable to connect "; - msg += src_port->full_name() + " -> " + dst_port->full_name(); - } - m_app->status_message(msg); + if (result == 0) + m_app->status_message(string("[JACK] Connected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[JACK] Unable to connect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } @@ -212,53 +287,74 @@ JackDriver::connect(const PatchagePort* const src_port, const PatchagePort* cons * \return Whether disconnection succeeded. */ bool -JackDriver::disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port) +JackDriver::disconnect(boost::shared_ptr<PatchagePort> const src_port, boost::shared_ptr<PatchagePort> const dst_port) { if (m_client == NULL) return false; int result = jack_disconnect(m_client, src_port->full_name().c_str(), dst_port->full_name().c_str()); - string msg; - - if (result == 0) { - msg = "Successfully disconnected jack ports"; - } else { - msg = "Unable to disconnect "; - msg += src_port->full_name() + " -> " + dst_port->full_name(); - } - m_app->status_message(msg); + if (result == 0) + m_app->status_message(string("[JACK] Disconnected ") + + src_port->full_name() + " -> " + dst_port->full_name()); + else + m_app->status_message(string("[JACK] Unable to disconnect ") + + src_port->full_name() + " -> " + dst_port->full_name()); return (!result); } void -JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int registered, void* me) +JackDriver::jack_port_registration_cb(jack_port_id_t port_id, int /*registered*/, void* jack_driver) { - assert(me != NULL); - assert(((JackDriver*)me)->m_client != NULL); - ((JackDriver*)me)->m_is_dirty = true; + assert(jack_driver); + JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver); + assert(me->m_client); + + jack_port_t* const port = jack_port_by_id(me->m_client, port_id); + const string full_name = jack_port_name(port); + + //(me->m_mutex).lock(); + + /*if (registered) { + me->m_added_ports.push_back(full_name); + } else { + me->m_removed_ports.push_back(full_name); + }*/ + + me->m_is_dirty = true; + + //(me->m_mutex).unlock(); } int -JackDriver::jack_graph_order_cb(void* me) +JackDriver::jack_graph_order_cb(void* jack_driver) { - assert(me != NULL); - assert(((JackDriver*)me)->m_client != NULL); - ((JackDriver*)me)->m_is_dirty = true; + assert(jack_driver); + JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver); + assert(me->m_client); + + //(me->m_mutex).lock(); + me->m_is_dirty = true; + //(me->m_mutex).unlock(); return 0; } void -JackDriver::jack_shutdown_cb(void* me) +JackDriver::jack_shutdown_cb(void* jack_driver) { - assert(me != NULL); - ((JackDriver*)me)->m_client = NULL; - ((JackDriver*)me)->m_is_dirty = true; + assert(jack_driver); + JackDriver* me = reinterpret_cast<JackDriver*>(jack_driver); + assert(me->m_client); + + //(me->m_mutex).lock(); + me->m_client = NULL; + me->m_is_dirty = true; + //(me->m_mutex).unlock(); } diff --git a/src/JackDriver.h b/src/JackDriver.h index 6b69900..db74f77 100644 --- a/src/JackDriver.h +++ b/src/JackDriver.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -18,12 +18,15 @@ #define JACKDRIVER_H #include <iostream> -#include <jack/jack.h> #include <string> +#include <boost/shared_ptr.hpp> +#include <jack/jack.h> +#include "Mutex.h" #include "Driver.h" class Patchage; class PatchageFlowCanvas; class PatchagePort; +class PatchageModule; using std::string; @@ -45,13 +48,11 @@ public: bool is_attached() const { return (m_client != NULL); } void refresh(); - bool connect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - bool disconnect(const PatchagePort* const src_port, const PatchagePort* const dst_port); - /*bool connect(const string& src_module_name, const string& src_port_name, - const string& dst_module_name, const string& dest_port_name); - - bool disconnect(const string& src_module_name, const string& src_port_name, - const string& dst_module_name, const string& dest_port_name);*/ + bool connect(boost::shared_ptr<PatchagePort> src, + boost::shared_ptr<PatchagePort> dst); + + bool disconnect(boost::shared_ptr<PatchagePort> src, + boost::shared_ptr<PatchagePort> dst); private: Patchage* m_app; @@ -59,6 +60,16 @@ private: jack_client_t* m_client; + Mutex m_mutex; + + list<string> m_added_ports; + list<string> m_removed_ports; + + boost::shared_ptr<PatchagePort> create_port(boost::shared_ptr<PatchageModule> parent, + jack_port_t* port); + + void destroy_all_ports(); + static void jack_port_registration_cb(jack_port_id_t port_id, int registered, void* controller); static int jack_graph_order_cb(void* controller); static void jack_shutdown_cb(void* controller); diff --git a/src/LashDriver.cpp b/src/LashDriver.cpp index c4a89b2..7989aa9 100644 --- a/src/LashDriver.cpp +++ b/src/LashDriver.cpp @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -44,25 +44,22 @@ LashDriver::~LashDriver() void LashDriver::attach(bool launch_daemon) { - cout << "Connecting to Lash... "; - cout.flush(); - - if (m_client != NULL) { - cout << "already connected." << endl; + // Already connected + if (m_client) return; - } int lash_flags = LASH_Config_File; if (launch_daemon) lash_flags |= LASH_No_Start_Server; m_client = lash_init(m_args, PACKAGE_NAME, lash_flags, LASH_PROTOCOL(2, 0)); if (m_client == NULL) { - cout << "Failed. Session management will not occur." << endl; + m_app->status_message("[LASH] Unable to attach to server"); } else { lash_event_t* event = lash_event_new_with_type(LASH_Client_Name); lash_event_set_string(event, "Patchage"); lash_send_event(m_client, event); - cout << "Connected" << endl; + signal_attached.emit(); + m_app->status_message("[LASH] Attached"); } } @@ -72,7 +69,8 @@ LashDriver::detach() { // FIXME: send some notification that we're gone?? m_client = NULL; - cout << "Disconnected from Lash" << endl; + m_app->status_message("[LASH] Detached"); + signal_detached.emit(); } diff --git a/src/LashDriver.h b/src/LashDriver.h index 742c249..9f361d7 100644 --- a/src/LashDriver.h +++ b/src/LashDriver.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -32,6 +32,12 @@ public: void detach(); bool is_attached() const { return lash_enabled(m_client); } + + bool connect(boost::shared_ptr<PatchagePort>, boost::shared_ptr<PatchagePort>) + { return false; } + + bool disconnect(boost::shared_ptr<PatchagePort>, boost::shared_ptr<PatchagePort>) + { return false; } void refresh() {} diff --git a/src/Makefile.am b/src/Makefile.am index 6e6eb5f..81529ab 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,6 +9,7 @@ dist_sharefiles_DATA = patchage.glade bin_PROGRAMS = patchage patchage_SOURCES = \ main.cpp \ + Mutex.h \ Patchage.h \ Patchage.cpp \ StateManager.h \ diff --git a/src/Patchage.cpp b/src/Patchage.cpp index d6e3a55..0a37e58 100644 --- a/src/Patchage.cpp +++ b/src/Patchage.cpp @@ -1,11 +1,11 @@ -/* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. +/* This file is part of Patchage. Copyright (C) 2006 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -58,7 +58,7 @@ Patchage::Patchage(int argc, char** argv) m_lash_driver = new LashDriver(this, argc, argv); #endif - Glib::RefPtr<Gnome::Glade::Xml> refXml; + Glib::RefPtr<Gnome::Glade::Xml> xml; // Check for the .glade file in current directory string glade_filename = "./patchage.glade"; @@ -77,57 +77,59 @@ Patchage::Patchage(int argc, char** argv) } try { - refXml = Gnome::Glade::Xml::create(glade_filename); + xml = Gnome::Glade::Xml::create(glade_filename); } catch(const Gnome::Glade::XmlError& ex) { std::cerr << ex.what() << std::endl; throw; } - refXml->get_widget("patchage_win", m_main_window); - refXml->get_widget("about_win", m_about_window); - refXml->get_widget("about_project_label", m_about_project_label); - refXml->get_widget("launch_jack_menuitem", m_menu_jack_launch); - refXml->get_widget("connect_to_jack_menuitem", m_menu_jack_connect); - refXml->get_widget("disconnect_from_jack_menuitem", m_menu_jack_disconnect); + xml->get_widget("patchage_win", m_main_window); + xml->get_widget("about_win", m_about_window); + xml->get_widget("launch_jack_menuitem", m_menu_jack_launch); + xml->get_widget("connect_to_jack_menuitem", m_menu_jack_connect); + xml->get_widget("disconnect_from_jack_menuitem", m_menu_jack_disconnect); #ifdef HAVE_LASH - refXml->get_widget("launch_lash_menuitem", m_menu_lash_launch); - refXml->get_widget("connect_to_lash_menuitem", m_menu_lash_connect); - refXml->get_widget("disconnect_from_lash_menuitem", m_menu_lash_disconnect); + xml->get_widget("launch_lash_menuitem", m_menu_lash_launch); + xml->get_widget("connect_to_lash_menuitem", m_menu_lash_connect); + xml->get_widget("disconnect_from_lash_menuitem", m_menu_lash_disconnect); #endif #ifdef HAVE_ALSA - refXml->get_widget("connect_to_alsa_menuitem", m_menu_alsa_connect); - refXml->get_widget("disconnect_from_alsa_menuitem", m_menu_alsa_disconnect); + xml->get_widget("connect_to_alsa_menuitem", m_menu_alsa_connect); + xml->get_widget("disconnect_from_alsa_menuitem", m_menu_alsa_disconnect); #endif - refXml->get_widget("file_save_menuitem", m_menu_file_save); - refXml->get_widget("file_quit_menuitem", m_menu_file_quit); - refXml->get_widget("view_refresh_menuitem", m_menu_view_refresh); - refXml->get_widget("help_about_menuitem", m_menu_help_about); - refXml->get_widget("canvas_scrolledwindow", m_canvas_scrolledwindow); - refXml->get_widget("zoom_scale", m_zoom_slider); - refXml->get_widget("about_close_button", m_about_close_button); - refXml->get_widget("status_lab", m_status_label); + xml->get_widget("store_positions_menuitem", m_menu_store_positions); + xml->get_widget("file_quit_menuitem", m_menu_file_quit); + xml->get_widget("view_refresh_menuitem", m_menu_view_refresh); + xml->get_widget("help_about_menuitem", m_menu_help_about); + xml->get_widget("canvas_scrolledwindow", m_canvas_scrolledwindow); + xml->get_widget("zoom_scale", m_zoom_slider); + xml->get_widget("status_text", m_status_text); + xml->get_widget("main_paned", m_main_paned); + xml->get_widget("zoom_full_but", m_zoom_full_button); + xml->get_widget("zoom_normal_but", m_zoom_normal_button); - m_main_window->resize( - static_cast<int>(m_state_manager->get_window_size().x), - static_cast<int>(m_state_manager->get_window_size().y)); - - m_main_window->move( - static_cast<int>(m_state_manager->get_window_location().x), - static_cast<int>(m_state_manager->get_window_location().y)); + update_state(); m_canvas_scrolledwindow->add(*m_canvas); //m_canvas_scrolledwindow->signal_event().connect(sigc::mem_fun(m_canvas, &FlowCanvas::scroll_event_handler)); m_canvas->scroll_to(static_cast<int>(m_canvas->width()/2 - 320), static_cast<int>(m_canvas->height()/2 - 240)); // FIXME: hardcoded - m_canvas->show(); - // Idle callback, check if we need to refresh (every 250msec) - Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 250); + // Idle callback, check if we need to refresh + Glib::signal_timeout().connect(sigc::mem_fun(this, &Patchage::idle_callback), 100); + + m_zoom_slider->signal_value_changed().connect(sigc::mem_fun(this, &Patchage::zoom_changed)); + m_zoom_normal_button->signal_clicked().connect(sigc::bind( + sigc::mem_fun(this, &Patchage::zoom), 1.0)); + + m_menu_jack_launch->signal_activate().connect(sigc::bind( + sigc::mem_fun(m_jack_driver, &JackDriver::attach), true)); + + m_menu_jack_connect->signal_activate().connect(sigc::bind( + sigc::mem_fun(m_jack_driver, &JackDriver::attach), false)); - m_zoom_slider->signal_value_changed().connect( sigc::mem_fun(this, &Patchage::zoom_changed)); - m_menu_jack_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_launch)); - m_menu_jack_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_jack_connect)); - m_menu_jack_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_jack_disconnect)); + m_menu_jack_disconnect->signal_activate().connect(sigc::mem_fun(m_jack_driver, &JackDriver::detach)); + #ifdef HAVE_LASH m_menu_lash_launch->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_launch)); m_menu_lash_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_lash_connect)); @@ -135,26 +137,29 @@ Patchage::Patchage(int argc, char** argv) #endif m_menu_alsa_connect->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_alsa_connect)); m_menu_alsa_disconnect->signal_activate().connect(sigc::mem_fun(this, &Patchage::menu_alsa_disconnect)); - m_menu_file_save->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_save)); + m_menu_store_positions->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_store_positions)); m_menu_file_quit->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_file_quit)); m_menu_view_refresh->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_view_refresh)); m_menu_help_about->signal_activate().connect( sigc::mem_fun(this, &Patchage::menu_help_about)); - m_about_close_button->signal_clicked().connect( sigc::mem_fun(this, &Patchage::close_about)); - //_about_project_label->use_markup(true); - m_about_project_label->set_markup("<span size=\"xx-large\" weight=\"bold\">Patchage " PACKAGE_VERSION "</span>"); + attach_menu_items(); + m_main_paned->set_position(m_main_paned->get_height() - 20); + + m_canvas->show(); } Patchage::~Patchage() { + delete m_jack_driver; +#ifdef HAVE_ALSA + delete m_alsa_driver; +#endif #ifdef HAVE_LASH delete m_lash_driver; #endif - delete m_jack_driver; - delete m_alsa_driver; - delete m_canvas; delete m_state_manager; + delete m_canvas; } @@ -170,7 +175,6 @@ Patchage::attach() m_alsa_driver->attach(); #endif - update_menu_items(); menu_view_refresh(); } @@ -178,19 +182,20 @@ Patchage::attach() bool Patchage::idle_callback() { - // FIXME: no need to destroy the whole canvas every time - if (m_refresh || (m_jack_driver && m_jack_driver->is_dirty()) + bool refresh = m_refresh; + + refresh = refresh || (m_jack_driver && m_jack_driver->is_dirty()); #ifdef HAVE_ALSA - || (m_alsa_driver && m_alsa_driver->is_dirty()) + refresh = refresh || (m_alsa_driver && m_alsa_driver->is_dirty()); #endif - ) { - m_canvas->destroy(); + + if (refresh) { + m_canvas->flag_all_connections(); + m_jack_driver->refresh(); #ifdef HAVE_ALSA m_alsa_driver->refresh(); #endif - update_menu_items(); - m_refresh = false; } #ifdef HAVE_LASH @@ -198,21 +203,31 @@ Patchage::idle_callback() m_lash_driver->process_events(); #endif + if (refresh) { + m_canvas->destroy_all_flagged_connections(); + m_refresh = false; + } + return true; } void -Patchage::zoom_changed() +Patchage::zoom(double z) { - const double z = m_zoom_slider->get_value(); - m_canvas->set_zoom(z); m_state_manager->set_zoom(z); } void +Patchage::zoom_changed() +{ + zoom(m_zoom_slider->get_value()); +} + + +void Patchage::update_state() { for (ModuleMap::iterator i = m_canvas->modules().begin(); i != m_canvas->modules().end(); ++i) @@ -236,10 +251,12 @@ Patchage::update_state() void Patchage::status_message(const string& msg) { - m_status_label->set_text(msg); -} - + if (m_status_text->get_buffer()->size() > 0) + m_status_text->get_buffer()->insert(m_status_text->get_buffer()->end(), "\n"); + m_status_text->get_buffer()->insert(m_status_text->get_buffer()->end(), msg); + m_status_text->scroll_to_mark(m_status_text->get_buffer()->get_insert(), 0); +} /** Update the sensitivity status of menus to reflect the present. @@ -247,61 +264,53 @@ Patchage::status_message(const string& msg) * (eg. disable "Connect to Jack" when Patchage is already connected to Jack) */ void -Patchage::update_menu_items() +Patchage::attach_menu_items() { - // Update Jack menu items - const bool jack_attached = m_jack_driver->is_attached(); - m_menu_jack_launch->set_sensitive(!jack_attached); - m_menu_jack_connect->set_sensitive(!jack_attached); - m_menu_jack_disconnect->set_sensitive(jack_attached); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_launch, &Gtk::MenuItem::set_sensitive), false)); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_connect, &Gtk::MenuItem::set_sensitive), false)); + m_lash_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_disconnect, &Gtk::MenuItem::set_sensitive), true)); - // Update Lash menu items -#ifdef HAVE_LASH - const bool lash_attached = m_lash_driver->is_attached(); - m_menu_lash_launch->set_sensitive(!lash_attached); - m_menu_lash_connect->set_sensitive(!lash_attached); - m_menu_lash_disconnect->set_sensitive(lash_attached); -#endif - -#ifdef HAVE_ALSA - // Update Alsa menu items - const bool alsa_attached = m_alsa_driver->is_attached(); - m_menu_alsa_connect->set_sensitive(!alsa_attached); - m_menu_alsa_disconnect->set_sensitive(alsa_attached); -#endif -} - - -void -Patchage::menu_jack_launch() -{ - m_jack_driver->attach(true); - update_menu_items(); -} - - -void -Patchage::menu_jack_connect() -{ - m_jack_driver->attach(false); - update_menu_items(); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_launch, &Gtk::MenuItem::set_sensitive), true)); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_connect, &Gtk::MenuItem::set_sensitive), true)); + m_lash_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_lash_disconnect, &Gtk::MenuItem::set_sensitive), false)); + + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), false)); + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_connect, &Gtk::MenuItem::set_sensitive), false)); + m_jack_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_disconnect, &Gtk::MenuItem::set_sensitive), true)); + + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_launch, &Gtk::MenuItem::set_sensitive), true)); + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_connect, &Gtk::MenuItem::set_sensitive), true)); + m_jack_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_jack_disconnect, &Gtk::MenuItem::set_sensitive), false)); + + m_alsa_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_connect, &Gtk::MenuItem::set_sensitive), false)); + m_alsa_driver->signal_attached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_disconnect, &Gtk::MenuItem::set_sensitive), true)); + + m_alsa_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_connect, &Gtk::MenuItem::set_sensitive), true)); + m_alsa_driver->signal_detached.connect(sigc::bind( + sigc::mem_fun(m_menu_alsa_disconnect, &Gtk::MenuItem::set_sensitive), false)); } -void -Patchage::menu_jack_disconnect() -{ - m_jack_driver->detach(); - menu_view_refresh(); - update_menu_items(); -} - #ifdef HAVE_LASH void Patchage::menu_lash_launch() { m_lash_driver->attach(true); - update_menu_items(); } @@ -309,7 +318,6 @@ void Patchage::menu_lash_connect() { m_lash_driver->attach(false); - update_menu_items(); } @@ -317,7 +325,6 @@ void Patchage::menu_lash_disconnect() { m_lash_driver->detach(); - update_menu_items(); } #endif @@ -326,7 +333,6 @@ void Patchage::menu_alsa_connect() { m_alsa_driver->attach(false); - update_menu_items(); } @@ -335,12 +341,11 @@ Patchage::menu_alsa_disconnect() { m_alsa_driver->detach(); menu_view_refresh(); - update_menu_items(); } #endif void -Patchage::menu_file_save() +Patchage::menu_store_positions() { store_window_location(); m_state_manager->save(m_settings_filename); @@ -363,7 +368,6 @@ Patchage::menu_view_refresh() { assert(m_canvas); - // FIXME: rebuilding the entire canvas each time is garbage m_canvas->destroy(); if (m_jack_driver) @@ -383,13 +387,6 @@ Patchage::menu_help_about() } -void -Patchage::close_about() -{ - m_about_window->hide(); -} - - /** Update the stored window location and size in the StateManager (in memory). */ void diff --git a/src/Patchage.h b/src/Patchage.h index f686e49..c7a3e0e 100644 --- a/src/Patchage.h +++ b/src/Patchage.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -57,16 +57,13 @@ public: inline void queue_refresh() { m_refresh = true; } protected: - void update_menu_items(); + void attach_menu_items(); - void menu_jack_launch(); - void menu_jack_connect(); - void menu_jack_disconnect(); - void menu_file_save(); + void menu_store_positions(); void menu_file_quit(); void menu_view_refresh(); void menu_help_about(); - void close_about(); + void zoom(double z); void zoom_changed(); bool idle_callback(); @@ -98,19 +95,20 @@ protected: bool m_refresh; Gtk::Window* m_main_window; - Gtk::Window* m_about_window; - Gtk::Label* m_about_project_label; + Gtk::AboutDialog* m_about_window; Gtk::MenuItem* m_menu_jack_launch; Gtk::MenuItem* m_menu_jack_connect; Gtk::MenuItem* m_menu_jack_disconnect; - Gtk::MenuItem* m_menu_file_save; + Gtk::MenuItem* m_menu_store_positions; Gtk::MenuItem* m_menu_file_quit; Gtk::MenuItem* m_menu_view_refresh; Gtk::MenuItem* m_menu_help_about; Gtk::ScrolledWindow* m_canvas_scrolledwindow; Gtk::HScale* m_zoom_slider; - Gtk::Button* m_about_close_button; - Gtk::Label* m_status_label; + Gtk::TextView* m_status_text; + Gtk::Paned* m_main_paned; + Gtk::Button* m_zoom_normal_button; + Gtk::Button* m_zoom_full_button; }; #endif // PATCHAGE_H diff --git a/src/PatchageFlowCanvas.cpp b/src/PatchageFlowCanvas.cpp index 2b9b19d..7485b6e 100644 --- a/src/PatchageFlowCanvas.cpp +++ b/src/PatchageFlowCanvas.cpp @@ -29,73 +29,72 @@ PatchageFlowCanvas::PatchageFlowCanvas(Patchage* app, int width, int height) } -PatchageModule* +boost::shared_ptr<PatchageModule> PatchageFlowCanvas::find_module(const string& name, ModuleType type) { - PatchageModule* pm = NULL; - for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) { - pm = (PatchageModule*)(*m).second; - if (pm->name() == name && pm->type() == type) { + boost::shared_ptr<PatchageModule> pm = boost::dynamic_pointer_cast<PatchageModule>((*m).second); + if (pm && pm->name() == name && pm->type() == type) { return pm; } } - return NULL; + return boost::shared_ptr<PatchageModule>(); } -PatchagePort* -PatchageFlowCanvas::find_port(const snd_seq_addr_t* alsa_addr, bool is_input) +boost::shared_ptr<PatchagePort> +PatchageFlowCanvas::find_port(const snd_seq_addr_t* alsa_addr) { - PatchagePort* pp = NULL; + boost::shared_ptr<PatchagePort> pp; for (ModuleMap::iterator m = m_modules.begin(); m != m_modules.end(); ++m) { - for (PortList::iterator p = (*m).second->ports().begin(); p != (*m).second->ports().end(); ++p) { - pp = (PatchagePort*)(*p); - if (pp->type() == ALSA_MIDI && pp->alsa_addr() + for (PortVector::const_iterator p = (*m).second->ports().begin(); p != (*m).second->ports().end(); ++p) { + pp = boost::dynamic_pointer_cast<PatchagePort>(*p); + if (pp && pp->type() == ALSA_MIDI && pp->alsa_addr() && pp->alsa_addr()->client == alsa_addr->client && pp->alsa_addr()->port == alsa_addr->port) - if (is_input == pp->is_input()) return pp; } } - return NULL; + return boost::shared_ptr<PatchagePort>(); } void -PatchageFlowCanvas::connect(const Port* port1, const Port* port2) +PatchageFlowCanvas::connect(boost::shared_ptr<Port> port1, boost::shared_ptr<Port> port2) { - PatchagePort* p1 = (PatchagePort*)port1; - PatchagePort* p2 = (PatchagePort*)port2; - + boost::shared_ptr<PatchagePort> p1 = boost::dynamic_pointer_cast<PatchagePort>(port1); + boost::shared_ptr<PatchagePort> p2 = boost::dynamic_pointer_cast<PatchagePort>(port2); + if (!p1 || !p2) + return; + if (p1->type() == JACK_AUDIO && p2->type() == JACK_AUDIO || (p1->type() == JACK_MIDI && p2->type() == JACK_MIDI)) - /*m_app->jack_driver()->connect(p1->module()->name(), p1->name(), - p2->module()->name(), p2->name());*/ m_app->jack_driver()->connect(p1, p2); else if (p1->type() == ALSA_MIDI && p2->type() == ALSA_MIDI) m_app->alsa_driver()->connect(p1, p2); else - m_app->status_message("Cannot make connection, incompatible port types."); + status_message("WARNING: Cannot make connection, incompatible port types."); } void -PatchageFlowCanvas::disconnect(const Port* port1, const Port* port2) +PatchageFlowCanvas::disconnect(boost::shared_ptr<Port> port1, boost::shared_ptr<Port> port2) { - PatchagePort* input = NULL; - PatchagePort* output = NULL; + boost::shared_ptr<PatchagePort> input; + boost::shared_ptr<PatchagePort> output; if (port1->is_input() && !port2->is_input()) { - input = (PatchagePort*)port1; - output = (PatchagePort*)port2; + input = boost::dynamic_pointer_cast<PatchagePort>(port1); + output = boost::dynamic_pointer_cast<PatchagePort>(port2); } else if (port2->is_input() && !port1->is_input()) { - input = (PatchagePort*)port2; - output = (PatchagePort*)port1; - } else { - m_app->status_message("Attempt to disconnect two input (or output) ports?? Please report bug."); + input = boost::dynamic_pointer_cast<PatchagePort>(port2); + output = boost::dynamic_pointer_cast<PatchagePort>(port1); + } + + if (!input || !output) { + status_message("ERROR: Attempt to disconnect mismatched/unknown ports"); return; } @@ -105,13 +104,13 @@ PatchageFlowCanvas::disconnect(const Port* port1, const Port* port2) else if (input->type() == ALSA_MIDI && output->type() == ALSA_MIDI) m_app->alsa_driver()->disconnect(output, input); else - m_app->status_message("Attempt to disconnect Jack audio port from Alsa Midi port?? Please report bug."); + status_message("ERROR: Attempt to disconnect ports with mismatched types"); } void PatchageFlowCanvas::status_message(const string& msg) { - m_app->status_message(msg); + m_app->status_message(string("[Canvas] ").append(msg)); } diff --git a/src/PatchageFlowCanvas.h b/src/PatchageFlowCanvas.h index 2636920..a99d658 100644 --- a/src/PatchageFlowCanvas.h +++ b/src/PatchageFlowCanvas.h @@ -33,11 +33,11 @@ class PatchageFlowCanvas : public FlowCanvas public: PatchageFlowCanvas(Patchage* m_app, int width, int height); - PatchageModule* find_module(const string& name, ModuleType type); - PatchagePort* find_port(const snd_seq_addr_t* alsa_addr, bool is_input); + boost::shared_ptr<PatchageModule> find_module(const string& name, ModuleType type); + boost::shared_ptr<PatchagePort> find_port(const snd_seq_addr_t* alsa_addr); - void connect(const Port* port1, const Port* port2); - void disconnect(const Port* port1, const Port* port2); + void connect(boost::shared_ptr<Port> port1, boost::shared_ptr<Port> port2); + void disconnect(boost::shared_ptr<Port> port1, boost::shared_ptr<Port> port2); void status_message(const string& msg); diff --git a/src/PatchageModule.h b/src/PatchageModule.h index 4400a68..58fa096 100644 --- a/src/PatchageModule.h +++ b/src/PatchageModule.h @@ -35,7 +35,7 @@ class PatchageModule : public Module { public: PatchageModule(Patchage* app, const string& title, ModuleType type, double x=0, double y=0) - : Module(app->canvas(), title, x, y), + : Module(*app->canvas(), title, x, y), m_app(app), m_type(type) { @@ -53,7 +53,7 @@ public: virtual ~PatchageModule() { } - virtual void add_patchage_port(const string& port_name, bool is_input, PortType type) + /*virtual void add_patchage_port(const string& port_name, bool is_input, PortType type) { new PatchagePort(this, type, port_name, is_input, m_app->state_manager()->get_port_color(type)); @@ -68,7 +68,7 @@ public: port->alsa_addr(addr); resize(); - } + }*/ virtual void load_location() { @@ -79,8 +79,8 @@ public: if (loc.x != -1) move_to(loc.x, loc.y); else - move_to((m_canvas->width()/2) - 100 + rand() % 400, - (m_canvas->height()/2) - 100 + rand() % 400); + move_to((m_canvas.width()/2) - 100 + rand() % 400, + (m_canvas.height()/2) - 100 + rand() % 400); } void split() { @@ -103,7 +103,7 @@ public: virtual void show_dialog() {} virtual void on_right_click(GdkEventButton* ev) { m_menu.popup(ev->button, ev->time); } virtual void menu_disconnect_all() { - for (PortList::iterator p = m_ports.begin(); p != m_ports.end(); ++p) + for (PortVector::iterator p = m_ports.begin(); p != m_ports.end(); ++p) (*p)->disconnect_all(); } diff --git a/src/PatchagePort.h b/src/PatchagePort.h index 601bce9..7ebc995 100644 --- a/src/PatchagePort.h +++ b/src/PatchagePort.h @@ -1,11 +1,11 @@ -/* This file is part of Om. Copyright (C) 2004 Dave Robillard. +/* This file is part of Patchage. Copyright (C) 2004 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -14,7 +14,6 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - #ifndef PATCHAGEPORT_H #define PATCHAGEPORT_H @@ -37,7 +36,7 @@ enum PortType { JACK_AUDIO, JACK_MIDI, ALSA_MIDI }; class PatchagePort : public LibFlowCanvas::Port { public: - PatchagePort(LibFlowCanvas::Module* module, PortType type, const string& name, bool is_input, int color) + PatchagePort(boost::shared_ptr<Module> module, PortType type, const string& name, bool is_input, int color) : Port(module, name, is_input, color), m_type(type) { @@ -53,7 +52,7 @@ public: { return (m_type == ALSA_MIDI) ? &m_alsa_addr : NULL; } /** Returns the full name of this port, as "modulename:portname" */ - string full_name() const { return m_module->name() + ":" + m_name; } + string full_name() const { return m_module.lock()->name() + ":" + m_name; } PortType type() const { return m_type; } diff --git a/src/StateManager.cpp b/src/StateManager.cpp index 50429e1..f4bab3a 100644 --- a/src/StateManager.cpp +++ b/src/StateManager.cpp @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * diff --git a/src/StateManager.h b/src/StateManager.h index b584308..06843bd 100644 --- a/src/StateManager.h +++ b/src/StateManager.h @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * diff --git a/src/main.cpp b/src/main.cpp index 5646b1c..a2da0ef 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,11 +1,11 @@ /* This file is part of Patchage. Copyright (C) 2005 Dave Robillard. * - * Om is free software; you can redistribute it and/or modify it under the + * Patchage is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * - * Om is distributed in the hope that it will be useful, but WITHOUT ANY + * Patchage is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details. * @@ -29,6 +29,12 @@ int main(int argc, char** argv) { try { + + //lash_args_t* const lash_args = lash_extract_args(&argc, &argv); + + //lash_client_t* const lash_server_client = lash_init(lash_args, "Patchage Server Interface", + // LASH_Server_Interface, LASH_PROTOCOL(2, 0)); + Gnome::Canvas::init(); Gtk::Main app(argc, argv); diff --git a/src/patchage.glade b/src/patchage.glade index 322a714..9bed33c 100644 --- a/src/patchage.glade +++ b/src/patchage.glade @@ -44,17 +44,17 @@ <widget class="GtkMenu" id="file_menu_menu"> <child> - <widget class="GtkImageMenuItem" id="launch_jack_menuitem"> + <widget class="GtkImageMenuItem" id="open_session_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Launch Jack</property> + <property name="label" translatable="yes">_Open Session</property> <property name="use_underline">True</property> - <signal name="activate" handler="on_launch_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:52:35 GMT"/> - <accelerator key="J" modifiers="GDK_CONTROL_MASK" signal="activate"/> + <signal name="activate" handler="on_open_session_menuitem_activate" last_modification_time="Sun, 01 Oct 2006 07:00:37 GMT"/> + <accelerator key="O" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image143"> + <widget class="GtkImage" id="image375"> <property name="visible">True</property> - <property name="stock">gtk-execute</property> + <property name="stock">gtk-open</property> <property name="icon_size">1</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> @@ -66,17 +66,17 @@ </child> <child> - <widget class="GtkImageMenuItem" id="connect_to_jack_menuitem"> + <widget class="GtkImageMenuItem" id="save_session_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Connect to _Jack</property> + <property name="label" translatable="yes">_Save Session</property> <property name="use_underline">True</property> - <signal name="activate" handler="on_connect_to_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:27:40 GMT"/> - <accelerator key="J" modifiers="GDK_MOD1_MASK" signal="activate"/> + <signal name="activate" handler="on_save_session_menuitem_activate" last_modification_time="Sun, 01 Oct 2006 07:01:40 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image144"> + <widget class="GtkImage" id="image376"> <property name="visible">True</property> - <property name="stock">gtk-connect</property> + <property name="stock">gtk-save</property> <property name="icon_size">1</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> @@ -88,17 +88,17 @@ </child> <child> - <widget class="GtkImageMenuItem" id="disconnect_from_jack_menuitem"> + <widget class="GtkImageMenuItem" id="save_session_as_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Disconnect from Jack</property> + <property name="label" translatable="yes">Save Session _As</property> <property name="use_underline">True</property> - <signal name="activate" handler="on_disconnect_from_jack1_activate" last_modification_time="Sun, 21 May 2006 23:48:26 GMT"/> - <accelerator key="J" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/> + <signal name="activate" handler="on_save_session_as_menuitem_activate" last_modification_time="Sun, 01 Oct 2006 07:01:40 GMT"/> + <accelerator key="S" modifiers="GDK_CONTROL_MASK | GDK_SHIFT_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image145"> + <widget class="GtkImage" id="image377"> <property name="visible">True</property> - <property name="stock">gtk-disconnect</property> + <property name="stock">gtk-save-as</property> <property name="icon_size">1</property> <property name="xalign">0.5</property> <property name="yalign">0.5</property> @@ -110,7 +110,7 @@ </child> <child> - <widget class="GtkSeparatorMenuItem" id="separator1"> + <widget class="GtkSeparatorMenuItem" id="separator5"> <property name="visible">True</property> </widget> </child> @@ -118,13 +118,13 @@ <child> <widget class="GtkImageMenuItem" id="launch_lash_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Launch Lash</property> + <property name="label" translatable="yes">Launch LASH</property> <property name="use_underline">True</property> <signal name="activate" handler="on_launch_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/> - <accelerator key="L" modifiers="GDK_CONTROL_MASK" signal="activate"/> + <accelerator key="L" modifiers="GDK_CONTROL_MASK | GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image146"> + <widget class="GtkImage" id="image378"> <property name="visible">True</property> <property name="stock">gtk-execute</property> <property name="icon_size">1</property> @@ -140,13 +140,13 @@ <child> <widget class="GtkImageMenuItem" id="connect_to_lash_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Connect to _Lash</property> + <property name="label" translatable="yes">Connect to _LASH</property> <property name="use_underline">True</property> <signal name="activate" handler="on_connect_to_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/> <accelerator key="L" modifiers="GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image147"> + <widget class="GtkImage" id="image379"> <property name="visible">True</property> <property name="stock">gtk-connect</property> <property name="icon_size">1</property> @@ -162,13 +162,85 @@ <child> <widget class="GtkImageMenuItem" id="disconnect_from_lash_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Disconnect from Lash</property> + <property name="label" translatable="yes">Disconnect from LASH</property> <property name="use_underline">True</property> <signal name="activate" handler="on_disconnect_from_lash1_activate" last_modification_time="Mon, 22 May 2006 01:14:33 GMT"/> <accelerator key="L" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image148"> + <widget class="GtkImage" id="image380"> + <property name="visible">True</property> + <property name="stock">gtk-disconnect</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkSeparatorMenuItem" id="separator1"> + <property name="visible">True</property> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="launch_jack_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Launch JACK</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_launch_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:52:35 GMT"/> + <accelerator key="J" modifiers="GDK_CONTROL_MASK | GDK_MOD1_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image381"> + <property name="visible">True</property> + <property name="stock">gtk-execute</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="connect_to_jack_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Connect to _JACK</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_connect_to_jack_menuitem_activate" last_modification_time="Wed, 05 Apr 2006 04:27:40 GMT"/> + <accelerator key="J" modifiers="GDK_MOD1_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image382"> + <property name="visible">True</property> + <property name="stock">gtk-connect</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> + + <child> + <widget class="GtkImageMenuItem" id="disconnect_from_jack_menuitem"> + <property name="visible">True</property> + <property name="label" translatable="yes">Disconnect from JACK</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_disconnect_from_jack1_activate" last_modification_time="Sun, 21 May 2006 23:48:26 GMT"/> + <accelerator key="J" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image383"> <property name="visible">True</property> <property name="stock">gtk-disconnect</property> <property name="icon_size">1</property> @@ -190,13 +262,13 @@ <child> <widget class="GtkImageMenuItem" id="connect_to_alsa_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Connect to _Alsa</property> + <property name="label" translatable="yes">Connect to _ALSA</property> <property name="use_underline">True</property> <signal name="activate" handler="on_connect_to_alsa_menuitem_activate" last_modification_time="Mon, 22 May 2006 00:10:31 GMT"/> <accelerator key="A" modifiers="GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image149"> + <widget class="GtkImage" id="image384"> <property name="visible">True</property> <property name="stock">gtk-connect</property> <property name="icon_size">1</property> @@ -212,13 +284,13 @@ <child> <widget class="GtkImageMenuItem" id="disconnect_from_alsa_menuitem"> <property name="visible">True</property> - <property name="label" translatable="yes">Disconnect from Alsa</property> + <property name="label" translatable="yes">Disconnect from ALSA</property> <property name="use_underline">True</property> <signal name="activate" handler="on_disconnect_from_alsa_menuitem_activate" last_modification_time="Mon, 22 May 2006 00:10:31 GMT"/> <accelerator key="A" modifiers="GDK_SHIFT_MASK | GDK_MOD1_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image150"> + <widget class="GtkImage" id="image385"> <property name="visible">True</property> <property name="stock">gtk-disconnect</property> <property name="icon_size">1</property> @@ -238,7 +310,7 @@ </child> <child> - <widget class="GtkImageMenuItem" id="file_save_menuitem"> + <widget class="GtkImageMenuItem" id="store_positions_menuitem"> <property name="visible">True</property> <property name="label" translatable="yes">_Store Positions</property> <property name="use_underline">True</property> @@ -246,7 +318,7 @@ <accelerator key="S" modifiers="GDK_CONTROL_MASK" signal="activate"/> <child internal-child="image"> - <widget class="GtkImage" id="image151"> + <widget class="GtkImage" id="image386"> <property name="visible">True</property> <property name="stock">gtk-save</property> <property name="icon_size">1</property> @@ -290,9 +362,22 @@ <child> <widget class="GtkImageMenuItem" id="view_refresh_menuitem"> <property name="visible">True</property> - <property name="label">gtk-refresh</property> - <property name="use_stock">True</property> - <signal name="activate" handler="on_item1_activate" last_modification_time="Sat, 11 Sep 2004 20:05:50 GMT"/> + <property name="label" translatable="yes">_Refresh</property> + <property name="use_underline">True</property> + <signal name="activate" handler="on_refresh2_activate" last_modification_time="Sat, 11 Sep 2004 20:05:50 GMT"/> + <accelerator key="R" modifiers="GDK_CONTROL_MASK" signal="activate"/> + + <child internal-child="image"> + <widget class="GtkImage" id="image387"> + <property name="visible">True</property> + <property name="stock">gtk-refresh</property> + <property name="icon_size">1</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> </widget> </child> </widget> @@ -330,272 +415,192 @@ </child> <child> - <widget class="GtkScrolledWindow" id="canvas_scrolledwindow"> + <widget class="GtkToolbar" id="toolbar1"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> - <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> - <property name="shadow_type">GTK_SHADOW_NONE</property> - <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + <property name="orientation">GTK_ORIENTATION_HORIZONTAL</property> + <property name="toolbar_style">GTK_TOOLBAR_ICONS</property> + <property name="tooltips">True</property> + <property name="show_arrow">True</property> <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> + <widget class="GtkToolItem" id="toolitem7"> + <property name="visible">True</property> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> - <child> - <widget class="GtkHBox" id="hbox1"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">0</property> + <child> + <widget class="GtkButton" id="zoom_normal_but"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> - <child> - <widget class="GtkLabel" id="status_lab"> - <property name="visible">True</property> - <property name="label" translatable="yes"></property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> + <child> + <widget class="GtkImage" id="zoom_normal_but_icon"> + <property name="visible">True</property> + <property name="stock">gtk-zoom-100</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> </widget> <packing> - <property name="padding">2</property> - <property name="expand">True</property> - <property name="fill">True</property> + <property name="expand">False</property> + <property name="homogeneous">False</property> </packing> </child> <child> - <widget class="GtkSeparatorToolItem" id="separatortoolitem1"> + <widget class="GtkToolItem" id="toolitem10"> <property name="visible">True</property> - <property name="draw">True</property> - <property name="visible_horizontal">False</property> + <property name="visible_horizontal">True</property> <property name="visible_vertical">True</property> + <property name="is_important">False</property> + + <child> + <widget class="GtkButton" id="zoom_full_but"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + + <child> + <widget class="GtkImage" id="image361"> + <property name="visible">True</property> + <property name="stock">gtk-zoom-fit</property> + <property name="icon_size">4</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + </child> + </widget> + </child> </widget> <packing> - <property name="padding">0</property> <property name="expand">False</property> - <property name="fill">False</property> + <property name="homogeneous">False</property> </packing> </child> <child> - <widget class="GtkHBox" id="hbox2"> + <widget class="GtkToolItem" id="toolitem1"> <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">0</property> - - <child> - <widget class="GtkLabel" id="label1"> - <property name="visible">True</property> - <property name="label" translatable="yes">Zoom: </property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> + <property name="visible_horizontal">True</property> + <property name="visible_vertical">True</property> + <property name="is_important">False</property> <child> <widget class="GtkHScale" id="zoom_scale"> <property name="width_request">150</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="draw_value">True</property> + <property name="draw_value">False</property> <property name="value_pos">GTK_POS_RIGHT</property> <property name="digits">1</property> <property name="update_policy">GTK_UPDATE_CONTINUOUS</property> <property name="inverted">False</property> - <property name="adjustment">1 0.1 2 0 0 0</property> + <property name="adjustment">1 0.10000000149 2 0 0 0</property> </widget> - <packing> - <property name="padding">5</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> </child> </widget> <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> + <property name="expand">True</property> + <property name="homogeneous">False</property> </packing> </child> </widget> <packing> - <property name="padding">2</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - </widget> - </child> -</widget> - -<widget class="GtkWindow" id="about_win"> - <property name="width_request">320</property> - <property name="height_request">200</property> - <property name="title" translatable="yes">About Patchage</property> - <property name="type">GTK_WINDOW_TOPLEVEL</property> - <property name="window_position">GTK_WIN_POS_CENTER_ON_PARENT</property> - <property name="modal">False</property> - <property name="resizable">False</property> - <property name="destroy_with_parent">False</property> - <property name="decorated">True</property> - <property name="skip_taskbar_hint">True</property> - <property name="skip_pager_hint">True</property> - <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> - <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> - <property name="focus_on_map">True</property> - <property name="urgency_hint">False</property> - - <child> - <widget class="GtkVBox" id="vbox1"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">0</property> - - <child> - <widget class="GtkLabel" id="about_project_label"> - <property name="visible">True</property> - <property name="label" translatable="yes"><span size="xx-large" weight="bold">Patchage</span></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label4"> - <property name="visible">True</property> - <property name="label" translatable="yes">A modular patch bay for: - -Jack Audio Connection Kit -ALSA Sequencer</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_CENTER</property> - <property name="wrap">True</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="label3"> - <property name="visible">True</property> - <property name="label" translatable="yes">Copyright © 2005 Dave Robillard</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="padding">10</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkHButtonBox" id="hbuttonbox1"> - <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> - <property name="spacing">0</property> - </widget> - <packing> <property name="padding">0</property> <property name="expand">False</property> - <property name="fill">False</property> + <property name="fill">True</property> </packing> </child> <child> - <widget class="GtkHButtonBox" id="hbuttonbox2"> + <widget class="GtkHBox" id="hbox1"> <property name="visible">True</property> - <property name="layout_style">GTK_BUTTONBOX_DEFAULT_STYLE</property> + <property name="homogeneous">False</property> <property name="spacing">0</property> <child> - <widget class="GtkButton" id="about_close_button"> - <property name="width_request">66</property> - <property name="height_request">26</property> + <widget class="GtkVPaned" id="main_paned"> + <property name="height_request">407</property> <property name="visible">True</property> <property name="can_focus">True</property> - <property name="label">gtk-close</property> - <property name="use_stock">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> + <property name="position">1</property> + + <child> + <widget class="GtkScrolledWindow" id="canvas_scrolledwindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="shrink">False</property> + <property name="resize">True</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow1"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTextView" id="status_text"> + <property name="visible">True</property> + <property name="sensitive">False</property> + <property name="can_focus">True</property> + <property name="editable">False</property> + <property name="overwrite">False</property> + <property name="accepts_tab">True</property> + <property name="justification">GTK_JUSTIFY_LEFT</property> + <property name="wrap_mode">GTK_WRAP_WORD</property> + <property name="cursor_visible">False</property> + <property name="pixels_above_lines">0</property> + <property name="pixels_below_lines">0</property> + <property name="pixels_inside_wrap">0</property> + <property name="left_margin">0</property> + <property name="right_margin">0</property> + <property name="indent">0</property> + <property name="text" translatable="yes"></property> + </widget> + </child> + </widget> + <packing> + <property name="shrink">True</property> + <property name="resize">True</property> + </packing> + </child> </widget> + <packing> + <property name="padding">2</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> </child> </widget> <packing> - <property name="padding">0</property> + <property name="padding">2</property> <property name="expand">True</property> <property name="fill">True</property> </packing> @@ -604,4 +609,29 @@ ALSA Sequencer</property> </child> </widget> +<widget class="GtkAboutDialog" id="about_win"> + <property name="destroy_with_parent">True</property> + <property name="name" translatable="yes">Patchage</property> + <property name="copyright" translatable="yes">© 2006 Dave Robillard</property> + <property name="comments" translatable="yes">A control centre for audio and music production systems</property> + <property name="license" translatable="yes">Patchage is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +Patchage is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Patchage; if not, write to the Free Software Foundation, Inc., +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +</property> + <property name="wrap_license">False</property> + <property name="website">http://codeson.net/software/patchage</property> + <property name="authors">Dave Robillard <dave@codeson.net></property> + <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with your names, one name per line.">translator-credits</property> +</widget> + </glade-interface> |