#include <cerrno>
#include <fstream>
+#include <stdarg.h>
+
#ifndef PLATFORM_WINDOWS
#include <sys/resource.h>
#endif
#include "pbd/file_utils.h"
#include "pbd/localtime_r.h"
#include "pbd/pthread_utils.h"
+#include "pbd/replace_all.h"
+#include "pbd/xml++.h"
#include "gtkmm2ext/application.h"
#include "gtkmm2ext/bindings.h"
typedef uint64_t microseconds_t;
#include "about.h"
+#include "editing.h"
#include "actions.h"
#include "add_route_dialog.h"
#include "ambiguous_file_dialog.h"
using namespace Gtkmm2ext;
using namespace Gtk;
using namespace std;
+using namespace Editing;
ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
sigc::signal<void, framepos_t, bool, framepos_t> ARDOUR_UI::Clock;
sigc::signal<void> ARDOUR_UI::CloseAllDialogs;
+float ARDOUR_UI::ui_scale = 1.0;
static bool
ask_about_configuration_copy (string const & old_dir, string const & new_dir, int version)
return (msg.run() == Gtk::RESPONSE_YES);
}
-ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir)
+static void
+libxml_generic_error_func (void* /* parsing_context*/,
+ const char* msg,
+ ...)
+{
+ va_list ap;
+ char buf[2048];
- : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
- , ui_config (new UIConfiguration)
- , gui_object_state (new GUIObjectState)
+ va_start (ap, msg);
+ vsnprintf (buf, sizeof (buf), msg, ap);
+ error << buf << endmsg;
+ va_end (ap);
+}
- , primary_clock (new MainClock (X_("primary"), false, X_("transport"), true, true, true, false, true))
- , secondary_clock (new MainClock (X_("secondary"), false, X_("secondary"), true, true, false, false, true))
-
- /* big clock */
+static void
+libxml_structured_error_func (void* /* parsing_context*/,
+ xmlErrorPtr err)
+{
+ string msg = err->message;
+
+ replace_all (msg, "\n", "");
+
+ error << X_("XML error: ") << msg << " in " << err->file << " at line " << err->line;
+ if (err->int2) {
+ error << ':' << err->int2;
+ }
+ error << endmsg;
+}
+
+ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], const char* localedir, UIConfiguration* uic)
+
+ : Gtkmm2ext::UI (PROGRAM_NAME, argcp, argvp)
+ , ui_config (uic->post_gui_init ())
+ , session_loaded (false)
+ , gui_object_state (new GUIObjectState)
+ , primary_clock (new MainClock (X_("primary"), X_("transport"), true ))
+ , secondary_clock (new MainClock (X_("secondary"), X_("secondary"), false))
, big_clock (new AudioClock (X_("bigclock"), false, "big", true, true, false, false))
, video_timeline(0)
-
- /* start of private members */
+ , ignore_dual_punch (false)
, editor (0)
, mixer (0)
, nsm (0)
, _was_dirty (false)
, _mixer_on_top (false)
, first_time_engine_run (true)
-
- /* transport */
-
, roll_controllable (new TransportControllable ("transport roll", *this, TransportControllable::Roll))
, stop_controllable (new TransportControllable ("transport stop", *this, TransportControllable::Stop))
, goto_start_controllable (new TransportControllable ("transport goto start", *this, TransportControllable::GotoStart))
, auto_loop_controllable (new TransportControllable ("transport auto loop", *this, TransportControllable::AutoLoop))
, play_selection_controllable (new TransportControllable ("transport play selection", *this, TransportControllable::PlaySelection))
, rec_controllable (new TransportControllable ("transport rec-enable", *this, TransportControllable::RecordEnable))
-
, auto_return_button (ArdourButton::led_default_elements)
, follow_edits_button (ArdourButton::led_default_elements)
, auto_input_button (ArdourButton::led_default_elements)
-
, auditioning_alert_button (_("Audition"))
, solo_alert_button (_("Solo"))
, feedback_alert_button (_("Feedback"))
, error_alert_button ( ArdourButton::just_led_default_elements )
-
, editor_meter(0)
, editor_meter_peak_display()
-
+ , session_selector_window (0)
+ , open_session_selector (0)
+ , _numpad_locate_happening (false)
+ , _session_is_new (false)
+ , last_key_press_time (0)
+ , save_as_dialog (0)
+ , meterbridge (0)
, speaker_config_window (X_("speaker-config"), _("Speaker Configuration"))
, key_editor (X_("key-editor"), _("Key Bindings"))
, rc_option_editor (X_("rc-options-editor"), _("Preferences"))
, big_clock_window (X_("big-clock"), _("Big Clock"), boost::bind (&ARDOUR_UI::create_big_clock_window, this))
, audio_port_matrix (X_("audio-connection-manager"), _("Audio Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::AUDIO))
, midi_port_matrix (X_("midi-connection-manager"), _("MIDI Connections"), boost::bind (&ARDOUR_UI::create_global_port_matrix, this, ARDOUR::DataType::MIDI))
-
+ , video_server_process (0)
+ , splash (0)
+ , have_configure_timeout (false)
+ , last_configure_time (0)
+ , last_peak_grab (0)
+ , have_disk_speed_dialog_displayed (false)
, _status_bar_visibility (X_("status-bar"))
, _feedback_exists (false)
, _log_not_acknowledged (LogLevelNone)
{
- Gtkmm2ext::init(localedir);
+ Gtkmm2ext::init (localedir);
if (ARDOUR::handle_old_configuration_files (boost::bind (ask_about_configuration_copy, _1, _2, _3))) {
MessageDialog msg (string_compose (_("Your configuration files were copied. You can now restart %1."), PROGRAM_NAME), true);
/* configuration was modified, exit immediately */
_exit (0);
}
-
- splash = 0;
-
- _numpad_locate_happening = false;
-
if (theArdourUI == 0) {
theArdourUI = this;
}
+ /* stop libxml from spewing to stdout/stderr */
+
+ xmlSetGenericErrorFunc (this, libxml_generic_error_func);
+ xmlSetStructuredErrorFunc (this, libxml_structured_error_func);
+
ui_config->ParameterChanged.connect (sigc::mem_fun (*this, &ARDOUR_UI::parameter_changed));
boost::function<void (string)> pc (boost::bind (&ARDOUR_UI::parameter_changed, this, _1));
ui_config->map_parameters (pc);
- editor = 0;
- mixer = 0;
- meterbridge = 0;
- editor = 0;
- _session_is_new = false;
- session_selector_window = 0;
- last_key_press_time = 0;
- video_server_process = 0;
- open_session_selector = 0;
- have_configure_timeout = false;
- have_disk_speed_dialog_displayed = false;
- session_loaded = false;
- ignore_dual_punch = false;
-
roll_button.set_controllable (roll_controllable);
stop_button.set_controllable (stop_controllable);
goto_start_button.set_controllable (goto_start_controllable);
rec_button.set_name ("transport recenable button");
midi_panic_button.set_name ("transport button");
- last_configure_time= 0;
- last_peak_grab = 0;
-
ARDOUR::Diskstream::DiskOverrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_overrun_handler, this), gui_context());
ARDOUR::Diskstream::DiskUnderrun.connect (forever_connections, MISSING_INVALIDATOR, boost::bind (&ARDOUR_UI::disk_underrun_handler, this), gui_context());
first_time_engine_run = false;
}
+ if (_session) {
+ _session->reset_xrun_count ();
+ }
update_disk_space ();
update_cpu_load ();
+ update_xrun_count ();
update_sample_rate (AudioEngine::instance()->sample_rate());
update_timecode_format ();
}
if ((nsm_url = g_getenv ("NSM_URL")) != 0) {
nsm = new NSM_Client;
if (!nsm->init (nsm_url)) {
- /* TODO this needs fixing!
+ /* the ardour executable may have different names:
+ *
* waf's obj.target for distro versions: eg ardour4, ardourvst4
* Ardour4, Mixbus3 for bundled versions + full path on OSX & windows
* argv[0] does not apply since we need the wrapper-script (not the binary itself)
- * No idea how to address all these.
+ *
+ * The wrapper startup script should set the environment variable 'ARDOUR_SELF'
*/
- nsm->announce (PROGRAM_NAME, ":dirty:", "ardour4");
+ const char *process_name = g_getenv ("ARDOUR_SELF");
+ nsm->announce (PROGRAM_NAME, ":dirty:", process_name ? process_name : "ardour4");
unsigned int i = 0;
// wait for announce reply from nsm server
ARDOUR_UI::every_second ()
{
update_cpu_load ();
+ update_xrun_count ();
update_buffer_load ();
update_disk_space ();
update_timecode_format ();
format_label.set_markup (s.str ());
}
+void
+ARDOUR_UI::update_xrun_count ()
+{
+ char buf[64];
+
+ /* If this text is changed, the set_size_request_to_display_given_text call in ARDOUR_UI::resize_text_widgets
+ should also be changed.
+ */
+
+ if (_session) {
+ const unsigned int x = _session->get_xrun_count ();
+ if (x > 9999) {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">>10K</span>"), X_("red"));
+ } else {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">%u</span>"), x > 0 ? X_("red") : X_("green"), x);
+ }
+ } else {
+ snprintf (buf, sizeof (buf), _("X: <span foreground=\"%s\">?</span>"), X_("yellow"));
+ }
+ xrun_label.set_markup (buf);
+ set_tip (xrun_label, _("Audio dropouts. Shift+click to reset"));
+}
+
void
ARDOUR_UI::update_cpu_load ()
{
void
ARDOUR_UI::toggle_roll (bool with_abort, bool roll_out_of_bounded_mode)
{
-
if (!_session) {
return;
}
if (!_session) return;
if (editor && !editor->dragging_playhead()) {
- Clock (_session->audible_frame(), false, editor->get_preferred_edit_position()); /* EMIT_SIGNAL */
+ Clock (_session->audible_frame(), false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD)); /* EMIT_SIGNAL */
}
}
return;
}
- SaveAsDialog sad;
+ if (!save_as_dialog) {
+ save_as_dialog = new SaveAsDialog;
+ } else {
+ save_as_dialog->clear_name ();
+ }
+
+ int response = save_as_dialog->run ();
- switch (sad.run()) {
+ save_as_dialog->hide ();
+
+ switch (response) {
case Gtk::RESPONSE_OK:
break;
default:
return;
}
- ArdourDialog progress_dialog(_("Save As"), true);
- Gtk::Label label;
- Gtk::ProgressBar progress_bar;
-
- progress_dialog.get_vbox()->pack_start (label);
- progress_dialog.get_vbox()->pack_start (progress_bar);
- label.show ();
- progress_bar.show ();
- Session::SaveAs sa;
-
- sa.new_parent_folder = sad.new_parent_folder ();
- sa.new_name = sad.new_name ();
- sa.switch_to = sad.switch_to();
- sa.copy_media = sad.copy_media();
- sa.copy_external = sad.copy_external();
-
- /* this signal will be emitted from within this, the calling thread,
- * after every file is copied. It provides information on percentage
- * complete (in terms of total data to copy), the number of files
- * copied so far, and the total number to copy.
- */
-
- ScopedConnection c;
-
- sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
+ Session::SaveAs sa;
+
+ sa.new_parent_folder = save_as_dialog->new_parent_folder ();
+ sa.new_name = save_as_dialog->new_name ();
+ sa.switch_to = save_as_dialog->switch_to();
+ sa.copy_media = save_as_dialog->copy_media();
+ sa.copy_external = save_as_dialog->copy_external();
+ sa.include_media = save_as_dialog->include_media ();
+
+ /* Only bother with a progress dialog if we're going to copy
+ media into the save-as target. Without that choice, this
+ will be very fast because we're only talking about a few kB's to
+ perhaps a couple of MB's of data.
+ */
- progress_dialog.show_all ();
- progress_dialog.present ();
+ ArdourDialog progress_dialog (_("Save As"), true);
+
+ if (sa.include_media && sa.copy_media) {
+
+ Gtk::Label label;
+ Gtk::ProgressBar progress_bar;
+
+ progress_dialog.get_vbox()->pack_start (label);
+ progress_dialog.get_vbox()->pack_start (progress_bar);
+ label.show ();
+ progress_bar.show ();
+
+ /* this signal will be emitted from within this, the calling thread,
+ * after every file is copied. It provides information on percentage
+ * complete (in terms of total data to copy), the number of files
+ * copied so far, and the total number to copy.
+ */
+
+ ScopedConnection c;
+
+ sa.Progress.connect_same_thread (c, boost::bind (&ARDOUR_UI::save_as_progress_update, this, _1, _2, _3, &label, &progress_bar));
+
+ progress_dialog.show_all ();
+ progress_dialog.present ();
+ }
if (_session->save_as (sa)) {
/* ERROR MESSAGE */
MessageDialog msg (string_compose (_("Save As failed: %1"), sa.failure_message));
msg.run ();
}
+
+ if (!sa.include_media) {
+ unload_session (false);
+ load_session (sa.final_session_folder_name, sa.new_name);
+ }
}
/** Ask the user for the name of a new snapshot and then take it.
void
ARDOUR_UI::create_xrun_marker (framepos_t where)
{
- editor->mouse_add_new_marker (where, false, true);
+ if (_session) {
+ Location *location = new Location (*_session, where, where, _("xrun"), Location::IsMark);
+ _session->locations()->add (location);
+ }
}
void
ARDOUR_UI::update_transport_clocks (framepos_t pos)
{
if (ui_config->get_primary_clock_delta_edit_cursor()) {
- primary_clock->set (pos, false, editor->get_preferred_edit_position());
+ primary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
} else {
primary_clock->set (pos);
}
if (ui_config->get_secondary_clock_delta_edit_cursor()) {
- secondary_clock->set (pos, false, editor->get_preferred_edit_position());
+ secondary_clock->set (pos, false, editor->get_preferred_edit_position (EDIT_IGNORE_PHEAD));
} else {
secondary_clock->set (pos);
}
break;
}
}
+
+void
+ARDOUR_UI::hide_application ()
+{
+ Application::instance ()-> hide ();
+}