summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2020-11-27 18:54:27 +0100
committerDavid Robillard <d@drobilla.net>2020-11-27 21:52:17 +0100
commitdbe6899651ac929f59af160dd07aaf6bda079b23 (patch)
tree49243cfa13dc3bba18526dc5eeb64f615a23c587
parent5dad45517e9dfa8b043f368cf31b2795fb713fde (diff)
downloadpatchage-dbe6899651ac929f59af160dd07aaf6bda079b23.tar.gz
patchage-dbe6899651ac929f59af160dd07aaf6bda079b23.tar.bz2
patchage-dbe6899651ac929f59af160dd07aaf6bda079b23.zip
Factor out log from Patchage class
Towards saner dependencies.
-rw-r--r--src/AlsaDriver.cpp47
-rw-r--r--src/AlsaDriver.hpp4
-rw-r--r--src/ILog.hpp41
-rw-r--r--src/JackDbusDriver.cpp7
-rw-r--r--src/JackDbusDriver.hpp6
-rw-r--r--src/JackDriver.cpp48
-rw-r--r--src/JackDriver.hpp8
-rw-r--r--src/Patchage.cpp67
-rw-r--r--src/Patchage.hpp8
-rw-r--r--src/PatchageCanvas.cpp9
-rw-r--r--src/PatchageEvent.cpp12
-rw-r--r--src/TextViewLog.cpp83
-rw-r--r--src/TextViewLog.hpp56
-rw-r--r--wscript1
14 files changed, 271 insertions, 126 deletions
diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp
index fc8fd34..a78c6ee 100644
--- a/src/AlsaDriver.cpp
+++ b/src/AlsaDriver.cpp
@@ -30,8 +30,9 @@ PATCHAGE_RESTORE_WARNINGS
#include <string>
#include <utility>
-AlsaDriver::AlsaDriver(Patchage* app)
+AlsaDriver::AlsaDriver(Patchage* app, ILog& log)
: _app(app)
+ , _log(log)
, _seq(nullptr)
, _refresh_thread{}
{}
@@ -47,10 +48,10 @@ AlsaDriver::attach(bool /*launch_daemon*/)
{
int ret = snd_seq_open(&_seq, "default", SND_SEQ_OPEN_DUPLEX, 0);
if (ret) {
- _app->error_msg("Alsa: Unable to attach.");
+ _log.error_msg("Alsa: Unable to attach.");
_seq = nullptr;
} else {
- _app->info_msg("Alsa: Attached.");
+ _log.info_msg("Alsa: Attached.");
snd_seq_set_client_name(_seq, "Patchage");
@@ -61,7 +62,7 @@ AlsaDriver::attach(bool /*launch_daemon*/)
ret = pthread_create(
&_refresh_thread, &attr, &AlsaDriver::refresh_main, this);
if (ret) {
- _app->error_msg("Alsa: Failed to start refresh thread.");
+ _log.error_msg("Alsa: Failed to start refresh thread.");
}
signal_attached.emit();
@@ -77,7 +78,7 @@ AlsaDriver::detach()
snd_seq_close(_seq);
_seq = nullptr;
signal_detached.emit();
- _app->info_msg("Alsa: Detached.");
+ _log.info_msg("Alsa: Detached.");
}
}
@@ -395,7 +396,7 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port)
PortAddrs::const_iterator d = _port_addrs.find(dst_port);
if (s == _port_addrs.end() || d == _port_addrs.end()) {
- _app->error_msg("Alsa: Attempt to connect port with no address.");
+ _log.error_msg("Alsa: Attempt to connect port with no address.");
return false;
}
@@ -404,7 +405,7 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port)
if (src.id.alsa_addr.client == dst.id.alsa_addr.client &&
src.id.alsa_addr.port == dst.id.alsa_addr.port) {
- _app->warning_msg("Alsa: Refusing to connect port to itself.");
+ _log.warning_msg("Alsa: Refusing to connect port to itself.");
return false;
}
@@ -420,23 +421,23 @@ AlsaDriver::connect(PatchagePort* src_port, PatchagePort* dst_port)
// Already connected (shouldn't happen)
if (!snd_seq_get_port_subscription(_seq, subs)) {
- _app->error_msg("Alsa: Attempt to double subscribe ports.");
+ _log.error_msg("Alsa: Attempt to double subscribe ports.");
result = false;
}
int ret = snd_seq_subscribe_port(_seq, subs);
if (ret < 0) {
- _app->error_msg(
+ _log.error_msg(
fmt::format("Alsa: Subscription failed ({}).", snd_strerror(ret)));
result = false;
}
if (result) {
- _app->info_msg(std::string("Alsa: Connected ") + src_port->full_name() +
- " => " + dst_port->full_name());
+ _log.info_msg(std::string("Alsa: Connected ") + src_port->full_name() +
+ " => " + dst_port->full_name());
} else {
- _app->error_msg(std::string("Alsa: Unable to connect ") +
- src_port->full_name() + " => " + dst_port->full_name());
+ _log.error_msg(std::string("Alsa: Unable to connect ") +
+ src_port->full_name() + " => " + dst_port->full_name());
}
return (!result);
@@ -453,7 +454,7 @@ AlsaDriver::disconnect(PatchagePort* src_port, PatchagePort* dst_port)
PortAddrs::const_iterator d = _port_addrs.find(dst_port);
if (s == _port_addrs.end() || d == _port_addrs.end()) {
- _app->error_msg("Alsa: Attempt to connect port with no address");
+ _log.error_msg("Alsa: Attempt to connect port with no address");
return false;
}
@@ -470,21 +471,21 @@ AlsaDriver::disconnect(PatchagePort* src_port, PatchagePort* dst_port)
// Not connected (shouldn't happen)
if (snd_seq_get_port_subscription(_seq, subs) != 0) {
- _app->error_msg(
+ _log.error_msg(
"Alsa: Attempt to unsubscribe ports that are not subscribed.");
return false;
}
int ret = snd_seq_unsubscribe_port(_seq, subs);
if (ret < 0) {
- _app->error_msg(std::string("Alsa: Unable to disconnect ") +
- src_port->full_name() + " => " + dst_port->full_name() +
- "(" + snd_strerror(ret) + ")");
+ _log.error_msg(std::string("Alsa: Unable to disconnect ") +
+ src_port->full_name() + " => " + dst_port->full_name() +
+ "(" + snd_strerror(ret) + ")");
return false;
}
- _app->info_msg(std::string("Alsa: Disconnected ") + src_port->full_name() +
- " => " + dst_port->full_name());
+ _log.info_msg(std::string("Alsa: Disconnected ") + src_port->full_name() +
+ " => " + dst_port->full_name());
return true;
}
@@ -503,7 +504,7 @@ AlsaDriver::create_refresh_port()
int ret = snd_seq_create_port(_seq, port_info);
if (ret) {
- _app->error_msg(
+ _log.error_msg(
fmt::format("Alsa: Error creating port ({})", snd_strerror(ret)));
return false;
}
@@ -514,7 +515,7 @@ AlsaDriver::create_refresh_port()
SND_SEQ_CLIENT_SYSTEM,
SND_SEQ_PORT_SYSTEM_ANNOUNCE);
if (ret) {
- _app->error_msg(
+ _log.error_msg(
fmt::format("Alsa: Failed to connect to system announce port ({})",
snd_strerror(ret)));
return false;
@@ -535,7 +536,7 @@ void
AlsaDriver::_refresh_main()
{
if (!create_refresh_port()) {
- _app->error_msg(
+ _log.error_msg(
"Alsa: Could not create listen port, auto-refresh disabled.");
return;
}
diff --git a/src/AlsaDriver.hpp b/src/AlsaDriver.hpp
index 2af3553..a953b7b 100644
--- a/src/AlsaDriver.hpp
+++ b/src/AlsaDriver.hpp
@@ -29,6 +29,7 @@
#include <set>
#include <string>
+class ILog;
class Patchage;
class PatchagePort;
@@ -37,7 +38,7 @@ class PatchagePort;
class AlsaDriver : public Driver
{
public:
- explicit AlsaDriver(Patchage* app);
+ explicit AlsaDriver(Patchage* app, ILog& log);
AlsaDriver(const AlsaDriver&) = delete;
AlsaDriver& operator=(const AlsaDriver&) = delete;
@@ -88,6 +89,7 @@ private:
snd_seq_addr_t addr);
Patchage* _app;
+ ILog& _log;
snd_seq_t* _seq;
pthread_t _refresh_thread;
diff --git a/src/ILog.hpp b/src/ILog.hpp
new file mode 100644
index 0000000..a71fda2
--- /dev/null
+++ b/src/ILog.hpp
@@ -0,0 +1,41 @@
+/* This file is part of Patchage.
+ * Copyright 2007-2020 David Robillard <d@drobilla.net>
+ *
+ * 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 3 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 details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Patchage. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PATCHAGE_ILOG_HPP
+#define PATCHAGE_ILOG_HPP
+
+#include <string>
+
+/// Interface for writing log messages
+class ILog
+{
+public:
+ ILog() = default;
+
+ ILog(const ILog&) = default;
+ ILog& operator=(const ILog&) = default;
+
+ ILog(ILog&&) = default;
+ ILog& operator=(ILog&&) = default;
+
+ virtual ~ILog() = default;
+
+ virtual void info_msg(const std::string& msg) = 0;
+ virtual void warning_msg(const std::string& msg) = 0;
+ virtual void error_msg(const std::string& msg) = 0;
+};
+
+#endif // PATCHAGE_ILOG_HPP
diff --git a/src/JackDbusDriver.cpp b/src/JackDbusDriver.cpp
index 7f9221b..8098410 100644
--- a/src/JackDbusDriver.cpp
+++ b/src/JackDbusDriver.cpp
@@ -54,8 +54,9 @@ PATCHAGE_RESTORE_WARNINGS
//#define USE_FULL_REFRESH
-JackDriver::JackDriver(Patchage* app)
+JackDriver::JackDriver(Patchage* app, ILog& log)
: _app(app)
+ , _log(log)
, _dbus_error()
, _dbus_connection(nullptr)
, _max_dsp_load(0.0f)
@@ -1190,11 +1191,11 @@ JackDriver::create_port_view(Patchage*, const PortID&)
void
JackDriver::error_msg(const std::string& msg) const
{
- _app->error_msg(std::string{"Jack: "} + msg);
+ _log.error_msg(std::string{"Jack: "} + msg);
}
void
JackDriver::info_msg(const std::string& msg) const
{
- _app->info_msg(std::string{"Jack: "} + msg);
+ _log.info_msg(std::string{"Jack: "} + msg);
}
diff --git a/src/JackDbusDriver.hpp b/src/JackDbusDriver.hpp
index aac7cd7..00c2a83 100644
--- a/src/JackDbusDriver.hpp
+++ b/src/JackDbusDriver.hpp
@@ -29,14 +29,15 @@
#include <string>
-class PatchageEvent;
+class ILog;
class PatchageCanvas;
+class PatchageEvent;
class PatchagePort;
class JackDriver : public Driver
{
public:
- explicit JackDriver(Patchage* app);
+ explicit JackDriver(Patchage* app, ILog& log);
JackDriver(const JackDriver&) = delete;
JackDriver& operator=(const JackDriver&) = delete;
@@ -143,6 +144,7 @@ private:
void on_jack_disappeared();
Patchage* _app;
+ ILog& _log;
DBusError _dbus_error;
DBusConnection* _dbus_connection;
float _max_dsp_load;
diff --git a/src/JackDriver.cpp b/src/JackDriver.cpp
index 29fedd8..8a44d93 100644
--- a/src/JackDriver.cpp
+++ b/src/JackDriver.cpp
@@ -16,6 +16,7 @@
#include "JackDriver.hpp"
+#include "ILog.hpp"
#include "Patchage.hpp"
#include "PatchageCanvas.hpp"
#include "PatchageEvent.hpp"
@@ -40,8 +41,9 @@ PATCHAGE_RESTORE_WARNINGS
#include <set>
#include <string>
-JackDriver::JackDriver(Patchage* app)
+JackDriver::JackDriver(Patchage* app, ILog& log)
: _app(app)
+ , _log(log)
, _client(nullptr)
, _events(128)
, _last_pos{}
@@ -73,7 +75,7 @@ JackDriver::attach(bool launch_daemon)
(!launch_daemon) ? JackNoStartServer : JackNullOption;
_client = jack_client_open("Patchage", options, nullptr);
if (_client == nullptr) {
- _app->error_msg("Jack: Unable to create client.");
+ _log.error_msg("Jack: Unable to create client.");
_is_activated = false;
} else {
jack_client_t* const client = _client;
@@ -92,9 +94,9 @@ JackDriver::attach(bool launch_daemon)
_is_activated = true;
signal_attached.emit();
std::stringstream ss;
- _app->info_msg("Jack: Attached.");
+ _log.info_msg("Jack: Attached.");
} else {
- _app->error_msg("Jack: Client activation failed.");
+ _log.error_msg("Jack: Client activation failed.");
_is_activated = false;
}
}
@@ -112,7 +114,7 @@ JackDriver::detach()
}
_is_activated = false;
signal_detached.emit();
- _app->info_msg("Jack: Detached.");
+ _log.info_msg("Jack: Detached.");
}
static bool
@@ -141,8 +143,8 @@ JackDriver::create_port_view(Patchage* patchage, const PortID& id)
jack_port_t* jack_port = jack_port_by_id(_client, id.id.jack_id);
if (!jack_port) {
- _app->error_msg(fmt::format("Jack: Failed to find port with ID `{}'.",
- id.id.jack_id));
+ _log.error_msg(fmt::format("Jack: Failed to find port with ID `{}'.",
+ id.id.jack_id));
return nullptr;
}
@@ -170,9 +172,9 @@ JackDriver::create_port_view(Patchage* patchage, const PortID& id)
}
if (parent->get_port(port_name)) {
- _app->error_msg(fmt::format("Jack: Module `{}' already has port `{}'.",
- module_name,
- port_name));
+ _log.error_msg(fmt::format("Jack: Module `{}' already has port `{}'.",
+ module_name,
+ port_name));
return nullptr;
}
@@ -243,9 +245,9 @@ JackDriver::create_port(PatchageModule& parent,
}
#endif
} else {
- _app->warning_msg(fmt::format("Jack: Port `{}' has unknown type `{}'.",
- jack_port_name(port),
- type_str));
+ _log.warning_msg(fmt::format("Jack: Port `{}' has unknown type `{}'.",
+ jack_port_name(port),
+ type_str));
return nullptr;
}
@@ -436,11 +438,11 @@ JackDriver::connect(PatchagePort* src_port, PatchagePort* dst_port)
_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
if (result == 0) {
- _app->info_msg(std::string("Jack: Connected ") + src_port->full_name() +
- " => " + dst_port->full_name());
+ _log.info_msg(std::string("Jack: Connected ") + src_port->full_name() +
+ " => " + dst_port->full_name());
} else {
- _app->error_msg(std::string("Jack: Unable to connect ") +
- src_port->full_name() + " => " + dst_port->full_name());
+ _log.error_msg(std::string("Jack: Unable to connect ") +
+ src_port->full_name() + " => " + dst_port->full_name());
}
return (!result);
@@ -462,11 +464,11 @@ JackDriver::disconnect(PatchagePort* const src_port,
_client, src_port->full_name().c_str(), dst_port->full_name().c_str());
if (result == 0) {
- _app->info_msg(std::string("Jack: Disconnected ") +
- src_port->full_name() + " => " + dst_port->full_name());
+ _log.info_msg(std::string("Jack: Disconnected ") +
+ src_port->full_name() + " => " + dst_port->full_name());
} else {
- _app->error_msg(std::string("Jack: Unable to disconnect ") +
- src_port->full_name() + " => " + dst_port->full_name());
+ _log.error_msg(std::string("Jack: Unable to disconnect ") +
+ src_port->full_name() + " => " + dst_port->full_name());
}
return (!result);
@@ -543,7 +545,7 @@ JackDriver::jack_shutdown_cb(void* jack_driver)
{
assert(jack_driver);
auto* me = static_cast<JackDriver*>(jack_driver);
- me->_app->info_msg("Jack: Shutdown.");
+ me->_log.info_msg("Jack: Shutdown.");
std::lock_guard<std::mutex> lock{me->_shutdown_mutex};
@@ -610,7 +612,7 @@ JackDriver::set_buffer_size(jack_nframes_t size)
}
if (jack_set_buffer_size(_client, size)) {
- _app->error_msg("[JACK] Unable to set buffer size");
+ _log.error_msg("[JACK] Unable to set buffer size");
return false;
}
diff --git a/src/JackDriver.hpp b/src/JackDriver.hpp
index 442ce74..0875703 100644
--- a/src/JackDriver.hpp
+++ b/src/JackDriver.hpp
@@ -26,11 +26,12 @@
#include <mutex>
#include <string>
+class ILog;
class Patchage;
-class PatchageEvent;
class PatchageCanvas;
-class PatchagePort;
+class PatchageEvent;
class PatchageModule;
+class PatchagePort;
/** Handles all externally driven functionality, registering ports etc.
*
@@ -40,7 +41,7 @@ class PatchageModule;
class JackDriver : public Driver
{
public:
- explicit JackDriver(Patchage* app);
+ explicit JackDriver(Patchage* app, ILog& log);
JackDriver(const JackDriver&) = delete;
JackDriver& operator=(const JackDriver&) = delete;
@@ -108,6 +109,7 @@ private:
static void jack_shutdown_cb(void* jack_driver);
Patchage* _app;
+ ILog& _log;
jack_client_t* _client;
Queue<PatchageEvent> _events;
diff --git a/src/Patchage.cpp b/src/Patchage.cpp
index 6a40c20..7fbc434 100644
--- a/src/Patchage.cpp
+++ b/src/Patchage.cpp
@@ -167,6 +167,7 @@ Patchage::Patchage(int argc, char** argv)
, INIT_WIDGET(_log_scrolledwindow)
, INIT_WIDGET(_status_text)
, _legend(nullptr)
+ , _log(_status_text)
, _pane_initialized(false)
, _attach(true)
, _driver_detached(false)
@@ -302,21 +303,6 @@ Patchage::Patchage(int argc, char** argv)
_menu_view_sprung_layout->set_sensitive(false);
}
- for (int s = Gtk::STATE_NORMAL; s <= Gtk::STATE_INSENSITIVE; ++s) {
- _status_text->modify_base(static_cast<Gtk::StateType>(s),
- Gdk::Color("#000000"));
- _status_text->modify_text(static_cast<Gtk::StateType>(s),
- Gdk::Color("#FFFFFF"));
- }
-
- _error_tag = Gtk::TextTag::create();
- _error_tag->property_foreground() = "#CC0000";
- _status_text->get_buffer()->get_tag_table()->add(_error_tag);
-
- _warning_tag = Gtk::TextTag::create();
- _warning_tag->property_foreground() = "#C4A000";
- _status_text->get_buffer()->get_tag_table()->add(_warning_tag);
-
_canvas->widget().show();
_main_win->present();
@@ -346,12 +332,12 @@ Patchage::Patchage(int argc, char** argv)
_about_win->set_logo(Gdk::Pixbuf::create_from_file(
bundle_location() + "/Resources/Patchage.icns"));
} catch (const Glib::Exception& e) {
- error_msg(fmt::format("failed to set logo ({})", e.what()));
+ _log.error_msg(fmt::format("failed to set logo ({})", e.what()));
}
#endif
#if defined(PATCHAGE_LIBJACK) || defined(HAVE_JACK_DBUS)
- _jack_driver = new JackDriver(this);
+ _jack_driver = new JackDriver(this, _log);
_jack_driver->signal_detached.connect(
sigc::mem_fun(this, &Patchage::driver_detached));
@@ -362,7 +348,7 @@ Patchage::Patchage(int argc, char** argv)
#endif
#ifdef HAVE_ALSA
- _alsa_driver = new AlsaDriver(this);
+ _alsa_driver = new AlsaDriver(this, _log);
#endif
connect_widgets();
@@ -370,10 +356,6 @@ Patchage::Patchage(int argc, char** argv)
_menu_view_toolbar->set_active(_conf->get_show_toolbar());
_menu_view_sprung_layout->set_active(_conf->get_sprung_layout());
_menu_view_sort_ports->set_active(_conf->get_sort_ports());
- _status_text->set_pixels_inside_wrap(2);
- _status_text->set_left_margin(4);
- _status_text->set_right_margin(4);
- _status_text->set_pixels_below_lines(2);
g_signal_connect(
_main_win->gobj(), "configure-event", G_CALLBACK(configure_cb), this);
@@ -594,32 +576,6 @@ Patchage::clear_load()
#endif
}
-void
-Patchage::error_msg(const std::string& msg)
-{
- Glib::RefPtr<Gtk::TextBuffer> buffer = _status_text->get_buffer();
- buffer->insert_with_tag(buffer->end(), std::string("\n") + msg, _error_tag);
- _status_text->scroll_to_mark(buffer->get_insert(), 0);
- _menu_view_messages->set_active(true);
-}
-
-void
-Patchage::info_msg(const std::string& msg)
-{
- Glib::RefPtr<Gtk::TextBuffer> buffer = _status_text->get_buffer();
- buffer->insert(buffer->end(), std::string("\n") + msg);
- _status_text->scroll_to_mark(buffer->get_insert(), 0);
-}
-
-void
-Patchage::warning_msg(const std::string& msg)
-{
- Glib::RefPtr<Gtk::TextBuffer> buffer = _status_text->get_buffer();
- buffer->insert_with_tag(
- buffer->end(), std::string("\n") + msg, _warning_tag);
- _status_text->scroll_to_mark(buffer->get_insert(), 0);
-}
-
static void
load_module_location(GanvNode* node, void*)
{
@@ -698,14 +654,14 @@ Patchage::show_open_session_dialog()
const std::string dir = dialog.get_filename();
if (g_chdir(dir.c_str())) {
- error_msg("Failed to switch to session directory " + dir);
+ _log.error_msg("Failed to switch to session directory " + dir);
return;
}
if (system("./jack-session") < 0) {
- error_msg("Error executing `./jack-session' in " + dir);
+ _log.error_msg("Error executing `./jack-session' in " + dir);
} else {
- info_msg("Loaded session " + dir);
+ _log.info_msg("Loaded session " + dir);
}
}
@@ -743,7 +699,7 @@ Patchage::save_session(bool close)
std::string path = dialog.get_filename();
if (g_mkdir_with_parents(path.c_str(), 0740)) {
- error_msg("Failed to create session directory " + path);
+ _log.error_msg("Failed to create session directory " + path);
return;
}
@@ -1056,13 +1012,8 @@ Patchage::on_view_messages()
if (_menu_view_messages->get_active()) {
Glib::RefPtr<Gtk::TextBuffer> buffer = _status_text->get_buffer();
if (!_pane_initialized) {
- int y = 0;
- int line_height = 0;
- _status_text->get_line_yrange(buffer->begin(), y, line_height);
-
- const int pad = _status_text->get_pixels_inside_wrap();
+ const int min_height = _log.min_height();
const int max_pos = _main_paned->get_allocation().get_height();
- const int min_height = (line_height + 2 * pad);
const int conf_height = _conf->get_messages_height();
_main_paned->set_position(max_pos -
std::max(conf_height, min_height));
diff --git a/src/Patchage.hpp b/src/Patchage.hpp
index 98537a1..e453b68 100644
--- a/src/Patchage.hpp
+++ b/src/Patchage.hpp
@@ -38,7 +38,9 @@
#include <gtkmm/viewport.h>
#include <gtkmm/window.h>
+#include "ILog.hpp"
#include "Legend.hpp"
+#include "TextViewLog.hpp"
#include "Widget.hpp"
#include "patchage_config.h"
@@ -70,6 +72,7 @@ public:
const std::shared_ptr<PatchageCanvas>& canvas() const { return _canvas; }
Gtk::Window* window() { return _main_win.get(); }
+ ILog& log() { return _log; }
Configuration* conf() const { return _conf; }
JackDriver* jack_driver() const { return _jack_driver; }
@@ -92,10 +95,6 @@ public:
inline void queue_refresh() { _refresh = true; }
inline void driver_detached() { _driver_detached = true; }
- void info_msg(const std::string& msg);
- void error_msg(const std::string& msg);
- void warning_msg(const std::string& msg);
-
void update_state();
void store_window_location();
@@ -210,6 +209,7 @@ protected:
Widget<Gtk::ScrolledWindow> _log_scrolledwindow;
Widget<Gtk::TextView> _status_text;
Legend* _legend;
+ TextViewLog _log;
Glib::RefPtr<Gtk::TextTag> _error_tag;
Glib::RefPtr<Gtk::TextTag> _warning_tag;
diff --git a/src/PatchageCanvas.cpp b/src/PatchageCanvas.cpp
index b6a592f..13eb0f4 100644
--- a/src/PatchageCanvas.cpp
+++ b/src/PatchageCanvas.cpp
@@ -246,7 +246,8 @@ PatchageCanvas::connect(Ganv::Node* port1, Ganv::Node* port2)
_app->alsa_driver()->connect(p1, p2);
#endif
} else {
- _app->warning_msg("Cannot make connection, incompatible port types.");
+ _app->log().warning_msg(
+ "Cannot make connection, incompatible port types.");
}
}
@@ -267,7 +268,8 @@ PatchageCanvas::disconnect(Ganv::Node* port1, Ganv::Node* port2)
}
if (!input || !output || input->is_output() || output->is_input()) {
- _app->error_msg("Attempt to disconnect mismatched/unknown ports.");
+ _app->log().error_msg(
+ "Attempt to disconnect mismatched/unknown ports.");
return;
}
@@ -283,7 +285,8 @@ PatchageCanvas::disconnect(Ganv::Node* port1, Ganv::Node* port2)
_app->alsa_driver()->disconnect(output, input);
#endif
} else {
- _app->error_msg("Attempt to disconnect ports with strange types.");
+ _app->log().error_msg(
+ "Attempt to disconnect ports with strange types.");
}
}
diff --git a/src/PatchageEvent.cpp b/src/PatchageEvent.cpp
index 4df2924..0f5645a 100644
--- a/src/PatchageEvent.cpp
+++ b/src/PatchageEvent.cpp
@@ -69,11 +69,11 @@ PatchageEvent::execute(Patchage* patchage)
if (driver) {
PatchagePort* port = driver->create_port_view(patchage, _port_1);
if (!port) {
- patchage->error_msg(fmt::format(
+ patchage->log().error_msg(fmt::format(
"Unable to create view for port `{}'", _port_1));
}
} else {
- patchage->error_msg(
+ patchage->log().error_msg(
fmt::format("Unknown type for port `{}'", _port_1));
}
@@ -87,10 +87,10 @@ PatchageEvent::execute(Patchage* patchage)
PatchagePort* port_2 = patchage->canvas()->find_port(_port_2);
if (!port_1) {
- patchage->error_msg(
+ patchage->log().error_msg(
fmt::format("Unable to find port `{}' to connect", _port_1));
} else if (!port_2) {
- patchage->error_msg(
+ patchage->log().error_msg(
fmt::format("Unable to find port `{}' to connect", _port_2));
} else {
patchage->canvas()->make_connection(port_1, port_2);
@@ -102,10 +102,10 @@ PatchageEvent::execute(Patchage* patchage)
PatchagePort* port_2 = patchage->canvas()->find_port(_port_2);
if (!port_1) {
- patchage->error_msg(
+ patchage->log().error_msg(
fmt::format("Unable to find port `{}' to disconnect", _port_1));
} else if (!port_2) {
- patchage->error_msg(
+ patchage->log().error_msg(
fmt::format("Unable to find port `{}' to disconnect", _port_2));
} else {
patchage->canvas()->remove_edge_between(port_1, port_2);
diff --git a/src/TextViewLog.cpp b/src/TextViewLog.cpp
new file mode 100644
index 0000000..b5e7a59
--- /dev/null
+++ b/src/TextViewLog.cpp
@@ -0,0 +1,83 @@
+/* This file is part of Patchage.
+ * Copyright 2007-2020 David Robillard <d@drobilla.net>
+ *
+ * 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 3 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 details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Patchage. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "TextViewLog.hpp"
+
+#include <glibmm/refptr.h>
+#include <gtkmm/textview.h>
+
+#include <string>
+
+TextViewLog::TextViewLog(Widget<Gtk::TextView>& text_view)
+ : _error_tag{Gtk::TextTag::create()}
+ , _warning_tag{Gtk::TextTag::create()}
+ , _text_view{text_view}
+{
+ for (int s = Gtk::STATE_NORMAL; s <= Gtk::STATE_INSENSITIVE; ++s) {
+ _text_view->modify_base(static_cast<Gtk::StateType>(s),
+ Gdk::Color("#000000"));
+ _text_view->modify_text(static_cast<Gtk::StateType>(s),
+ Gdk::Color("#FFFFFF"));
+ }
+
+ _error_tag->property_foreground() = "#CC0000";
+ _text_view->get_buffer()->get_tag_table()->add(_error_tag);
+
+ _warning_tag->property_foreground() = "#C4A000";
+ _text_view->get_buffer()->get_tag_table()->add(_warning_tag);
+
+ _text_view->set_pixels_inside_wrap(2);
+ _text_view->set_left_margin(4);
+ _text_view->set_right_margin(4);
+ _text_view->set_pixels_below_lines(2);
+}
+
+void
+TextViewLog::info_msg(const std::string& msg)
+{
+ Glib::RefPtr<Gtk::TextBuffer> buffer = _text_view->get_buffer();
+ buffer->insert(buffer->end(), std::string("\n") + msg);
+ _text_view->scroll_to_mark(buffer->get_insert(), 0);
+}
+
+void
+TextViewLog::warning_msg(const std::string& msg)
+{
+ Glib::RefPtr<Gtk::TextBuffer> buffer = _text_view->get_buffer();
+ buffer->insert_with_tag(
+ buffer->end(), std::string("\n") + msg, _warning_tag);
+ _text_view->scroll_to_mark(buffer->get_insert(), 0);
+}
+
+void
+TextViewLog::error_msg(const std::string& msg)
+{
+ Glib::RefPtr<Gtk::TextBuffer> buffer = _text_view->get_buffer();
+ buffer->insert_with_tag(buffer->end(), std::string("\n") + msg, _error_tag);
+ _text_view->scroll_to_mark(buffer->get_insert(), 0);
+}
+
+int
+TextViewLog::min_height() const
+{
+ Glib::RefPtr<Gtk::TextBuffer> buffer = _text_view->get_buffer();
+
+ int y = 0;
+ int line_height = 0;
+ _text_view->get_line_yrange(buffer->begin(), y, line_height);
+
+ return line_height + 2 * _text_view->get_pixels_inside_wrap();
+}
diff --git a/src/TextViewLog.hpp b/src/TextViewLog.hpp
new file mode 100644
index 0000000..eb44407
--- /dev/null
+++ b/src/TextViewLog.hpp
@@ -0,0 +1,56 @@
+/* This file is part of Patchage.
+ * Copyright 2007-2020 David Robillard <d@drobilla.net>
+ *
+ * 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 3 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 details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Patchage. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef PATCHAGE_TEXTVIEWLOG_HPP
+#define PATCHAGE_TEXTVIEWLOG_HPP
+
+#include "ILog.hpp"
+#include "Widget.hpp"
+
+#include <glibmm/refptr.h>
+#include <gtkmm/texttag.h>
+#include <gtkmm/textview.h>
+
+/// Log that writes colored messages to a Gtk TextView
+class TextViewLog : public ILog
+{
+public:
+ explicit TextViewLog(Widget<Gtk::TextView>& text_view);
+
+ TextViewLog(const TextViewLog&) = delete;
+ TextViewLog& operator=(const TextViewLog&) = delete;
+
+ TextViewLog(TextViewLog&&) = delete;
+ TextViewLog& operator=(TextViewLog&&) = delete;
+
+ ~TextViewLog() override = default;
+
+ void info_msg(const std::string& msg) override;
+ void error_msg(const std::string& msg) override;
+ void warning_msg(const std::string& msg) override;
+
+ int min_height() const;
+
+ const Widget<Gtk::TextView>& text_view() const { return _text_view; }
+ Widget<Gtk::TextView>& text_view() { return _text_view; }
+
+private:
+ Glib::RefPtr<Gtk::TextTag> _error_tag;
+ Glib::RefPtr<Gtk::TextTag> _warning_tag;
+ Widget<Gtk::TextView>& _text_view;
+};
+
+#endif // PATCHAGE_TEXTVIEWLOG_HPP
diff --git a/wscript b/wscript
index cf876ac..2d80c4e 100644
--- a/wscript
+++ b/wscript
@@ -244,6 +244,7 @@ def build(bld):
src/PatchageCanvas.cpp
src/PatchageEvent.cpp
src/PatchageModule.cpp
+ src/TextViewLog.cpp
src/main.cpp
'''
if bld.is_defined('HAVE_JACK_DBUS'):