diff --git a/biotracker/BioTrackerApp.h b/biotracker/BioTrackerApp.h
index e72e3d52d5ef669d37b8c649aad42df9179cb177..7f825109753757a262424cdec1c710eb5a395187 100644
--- a/biotracker/BioTrackerApp.h
+++ b/biotracker/BioTrackerApp.h
@@ -15,6 +15,7 @@
 #include "settings/Settings.h"
 #include "TrackerStatus.h"
 #include "PanZoomState.h"
+#include "zmq/ZmqProcessHandler.h"
 
 namespace BioTracker {
 namespace Core {
diff --git a/biotracker/ZmqTrackingAlgorithm.h b/biotracker/ZmqTrackingAlgorithm.h
index 8f6eed1c71dac42ae9ce483074a3f45c41a94330..2289793606870ba6e913a80d8174aa68bd1f0ea2 100644
--- a/biotracker/ZmqTrackingAlgorithm.h
+++ b/biotracker/ZmqTrackingAlgorithm.h
@@ -24,6 +24,7 @@
 #include "Exceptions.h"
 
 #include "zmq/ZmqInfoFile.h"
+#include "zmq/ZmqClientProcess.h"
 
 namespace BioTracker {
 namespace Core {
@@ -32,7 +33,7 @@ namespace Zmq {
 class ZmqTrackingAlgorithm : public TrackingAlgorithm {
 
   public:
-    ZmqTrackingAlgorithm(ZmqInfoFile info, Settings &settings);
+    ZmqTrackingAlgorithm(std::shared_ptr<ZmqClientProcess> process, Settings &settings);
 
     virtual ~ZmqTrackingAlgorithm() override;
 
@@ -61,25 +62,18 @@ class ZmqTrackingAlgorithm : public TrackingAlgorithm {
 
     void keyPressEvent(QKeyEvent *) override;
 
-    void listenToEvents();
-
     void shutdown();
 
   private Q_SLOTS:
-    void btnClicked();
-    void sldValueChanged(int value);
-    void processError(QProcess::ProcessError error);
-    void processHasError();
+    void btnClicked(const QString);
+    void sldValueChanged(const QString, int value);
 
   private:
-    std::unique_ptr<QProcess> m_zmqClient;
-    bool m_isDead; // if this is true: its OVER
     bool m_isTracking;
     std::set<Qt::Key> m_keys;
-    void *m_context;
-    void *m_socket;
     std::shared_ptr<QWidget> m_tools;
-    std::mutex m_zmqMutex;
+    std::shared_ptr<ZmqClientProcess> m_process;
+    EventHandler m_events;
 };
 }
 }
diff --git a/biotracker/src/Registry.cpp b/biotracker/src/Registry.cpp
index 21211a13d5b4048be40e896317ee4a523f06d338..3cd6e53714aefd962ce046a27c967eebb5e3109e 100644
--- a/biotracker/src/Registry.cpp
+++ b/biotracker/src/Registry.cpp
@@ -6,6 +6,8 @@
 #include <QLibrary>
 
 #include "Exceptions.h"
+#include "biotracker/zmq/ZmqProcessHandler.h"
+#include "biotracker/zmq/ZmqClientProcess.h"
 
 namespace BioTracker {
 namespace Core {
@@ -78,7 +80,9 @@ std::shared_ptr<TrackingAlgorithm> Registry::makeNewTracker(
 
 std::shared_ptr<TrackingAlgorithm> Registry::getTracker(Zmq::ZmqInfoFile &info,
         Settings &s) const {
-    auto tracker = std::make_shared<Zmq::ZmqTrackingAlgorithm>(info, s);
+    Zmq::ZmqProcessHandler &handler = Zmq::ZmqProcessHandler::getInstance();
+    std::shared_ptr<Zmq::ZmqClientProcess> proc = handler.startProcess(info);
+    auto tracker = std::make_shared<Zmq::ZmqTrackingAlgorithm>(proc, s);
     return tracker;
 }
 
@@ -97,7 +101,10 @@ bool BioTracker::Core::Registry::registerZmqTracker(Zmq::ZmqInfoFile
 
         virtual std::shared_ptr<TrackingAlgorithm> operator()(Settings &settings)
         const override {
-            return std::make_shared<Zmq::ZmqTrackingAlgorithm>(m_trackerInfo, settings);
+            Zmq::ZmqProcessHandler &zmqhandler = Zmq::ZmqProcessHandler::getInstance();
+            Zmq::ZmqInfoFile info = m_trackerInfo;
+            std::shared_ptr<Zmq::ZmqClientProcess> proc = zmqhandler.startProcess(info);
+            return std::make_shared<Zmq::ZmqTrackingAlgorithm>(proc, settings);
         }
 
         Zmq::ZmqInfoFile m_trackerInfo;
diff --git a/biotracker/src/ZmqTrackingAlgorithm.cpp b/biotracker/src/ZmqTrackingAlgorithm.cpp
index 50a3807b888d52f5292639a54f5b1247ac5f5d11..a62ad389dccb6e25247ef16eeea135295c8a9c75 100644
--- a/biotracker/src/ZmqTrackingAlgorithm.cpp
+++ b/biotracker/src/ZmqTrackingAlgorithm.cpp
@@ -1,76 +1,40 @@
 #include "../ZmqTrackingAlgorithm.h"
 
-#include "zmq/ZmqInfoFile.h"
+#include "biotracker/zmq/ZmqInfoFile.h"
 #include "biotracker/zmq/ZmqHelper.h"
+#include "biotracker/zmq/ZmqMessageParser.h"
 
 namespace BioTracker {
 namespace Core {
 namespace Zmq {
 
-const QString TYPE_TRACK("0");
-const QString TYPE_PAINT("1");
-const QString TYPE_SHUTDOWN("2");
-const QString TYPE_PAINTOVERLAY("3");
-const QString TYPE_REQUEST_WIDGETS("4");
-const QString TYPE_SEND_WIDGET_EVENT("5");
-
-const QString WIDGET_EVENT_CLICK("0");
-const QString WIDGET_EVENT_CHANGED("1");
-
-const QString EVENT_STOP_LISTENING("99");
-const QString EVENT_NOTIFY_GUI("0");
-const QString EVENT_UPDATE("1");
-const QString EVENT_FORCE_TRACKING("2");
-const QString EVENT_JUMP_TO_FRAME("3");
-const QString EVENT_PLAY_PAUSE("4");
-
-const QString EVENT_MSG_FALSE("0");
-
-
-const int ZMQ_TIMEOUT_IN_MS = 10000; // timeout for the zmq tracker during execution
-const int ZMQ_SMALL_TIMEOUT_IN_MS = 1000; // timeout for the startup of the zmq tracker
-
-inline QString getSenderId(QObject *obj) {
-    QWidget *w = qobject_cast<QWidget *>(obj);
-    return w->accessibleName();
-}
 
 inline void setSenderId(QWidget *w, const QString id) {
     w->setAccessibleName(id);
 }
 
-
-ZmqTrackingAlgorithm::ZmqTrackingAlgorithm(ZmqInfoFile info, Settings &settings) :
+/**
+ * @brief ZmqTrackingAlgorithm::ZmqTrackingAlgorithm
+ * @param process
+ * @param settings
+ */
+ZmqTrackingAlgorithm::ZmqTrackingAlgorithm(std::shared_ptr<ZmqClientProcess> process, Settings &settings) :
     TrackingAlgorithm(settings),
     m_isTracking(false),
-    m_context(zmq_ctx_new()),
-    m_socket(zmq_socket(m_context, ZMQ_PAIR)),
-    m_tools(std::make_shared<QFrame>()) {
-
-    // set timeout
-    zmq_setsockopt(m_socket, ZMQ_RCVTIMEO, &ZMQ_SMALL_TIMEOUT_IN_MS, sizeof(int));
-
-    int rc = zmq_bind(m_socket, "tcp://127.0.0.1:5556");
-    if (rc != 0) {
-        int rno = zmq_errno();
-        QString err_msg(zmq_strerror(rno));
-        std::cout << "error: " << err_msg.toUtf8().constData() << std::endl;
-    }
-    assert(rc == 0);
-    m_zmqClient = std::make_unique<QProcess>(this);
-    m_zmqClient->setProcessChannelMode(QProcess::ForwardedChannels);
-    QString command = info.m_program + " " + info.m_arguments.first();
-
-    // connect listeners
-    QObject::connect(m_zmqClient.get(), &QProcess::readyReadStandardError,
-                     this, &ZmqTrackingAlgorithm::processHasError);
-
-    QObject::connect(m_zmqClient.get(),
-                     static_cast<void(QProcess::*)(QProcess::ProcessError)>(&QProcess::error),
-                     this, &ZmqTrackingAlgorithm::processError);
-
-    m_zmqClient->start(command);
-    m_zmqClient->waitForStarted();
+    m_tools(std::make_shared<QFrame>()),
+    m_process(process),
+    m_events(this) {
+
+    // ATTACH EVENTS
+    QObject::connect(&m_events, &EventHandler::btnClicked, this, &ZmqTrackingAlgorithm::btnClicked);
+    QObject::connect(&m_events, &EventHandler::sldValueChanged, this, &ZmqTrackingAlgorithm::sldValueChanged);
+
+    QObject::connect(&m_events, &EventHandler::notifyGUI, this, &ZmqTrackingAlgorithm::notifyGUI);
+    QObject::connect(&m_events, &EventHandler::update, this, &ZmqTrackingAlgorithm::update);
+    QObject::connect(&m_events, &EventHandler::forceTracking, this, &ZmqTrackingAlgorithm::forceTracking);
+    QObject::connect(&m_events, &EventHandler::pausePlayback, this, &ZmqTrackingAlgorithm::pausePlayback);
+    QObject::connect(&m_events, &EventHandler::jumpToFrame, this, &ZmqTrackingAlgorithm::jumpToFrame);
+
 }
 
 ZmqTrackingAlgorithm::~ZmqTrackingAlgorithm() {
@@ -78,98 +42,23 @@ ZmqTrackingAlgorithm::~ZmqTrackingAlgorithm() {
 }
 
 void ZmqTrackingAlgorithm::track(ulong frameNumber, const cv::Mat &frame) {
-    if (m_isDead) {
-        return;
-    }
-    m_zmqMutex.lock();
-    send_string(m_socket, TYPE_TRACK, ZMQ_SNDMORE);
-    send_mat(m_socket, frame, frameNumber);
-    this->listenToEvents();
-    m_isTracking = true;
-    m_zmqMutex.unlock();
+    SendTrackMessage message(frame, frameNumber);
+    m_process->send(message, m_events);
 }
 
-void ZmqTrackingAlgorithm::paint(ProxyMat &m, const View &) {
-    if (m_isDead) {
-        return;
-    }
-    m_zmqMutex.lock();
-    send_string(m_socket, TYPE_PAINT, ZMQ_SNDMORE);
-    QString data = QString::number(99);
-    send_string(m_socket, data, 0);
-    this->listenToEvents();
-    // wait for reply
-    QString flag = recv_string(m_socket);
-    if (QString::compare(flag, "Y") == 0) {
-        recv_mat(m_socket, m.getMat());
-    }
-    m_zmqMutex.unlock();
+void ZmqTrackingAlgorithm::paint(ProxyMat &m, const View &v) {
+    SendPaintMessage message(99, v.name, m.getMat());
+    m_process->send(message, m_events);
 }
 
-void ZmqTrackingAlgorithm::paintOverlay(QPainter *p, const View &) {
-    if (m_isDead) {
-        return;
-    }
-    m_zmqMutex.lock();
-    send_string(m_socket, TYPE_PAINTOVERLAY, 0);
-    this->listenToEvents();
-    //recv_QPainter(m_socket, p);
-    m_zmqMutex.unlock();
+void ZmqTrackingAlgorithm::paintOverlay(QPainter *p, const View &v) {
+    SendPaintOverlayMessage message(v.name, p);
+    m_process->send(message, m_events);
 }
 
 std::shared_ptr<QWidget> ZmqTrackingAlgorithm::getToolsWidget() {
-    m_zmqMutex.lock();
-
-    // request widgets from client
-    send_string(m_socket, TYPE_REQUEST_WIDGETS, 0);
-    this->listenToEvents();
-
-    QVBoxLayout *mainLayout = new QVBoxLayout(m_tools.get()); // LEAK_CHECK?
-
-    // wait for response
-    // Elements are defined at:
-    // https://github.com/BioroboticsLab/biotracker_core/wiki/dev_zmq#possible-elements
-    QString data = recv_string(m_socket);
-    if (data.length() > 0) {
-        QStringList batch = data.split(";");
-        for (auto &widgetStr : batch) {
-            const QChar type = widgetStr.at(0);
-            widgetStr.chop(1); // remove trailing ')'
-            widgetStr = widgetStr.right(widgetStr.length() - 2); // remove first '_('
-            auto widgetElems = widgetStr.split(",");
-            const QString uniqueId = widgetElems[0];
-            if (type == QChar('d')) {
-
-            } else if (type == QChar('t')) {
-                QLabel *txt = new QLabel(m_tools.get());
-                txt->setText(widgetElems[1]);
-                mainLayout->addWidget(txt);
-            } else if (type == QChar('b')) {
-                QPushButton *btn = new QPushButton(m_tools.get()); // LEAK_CHECK?
-                btn->setText(widgetElems[1]);
-                setSenderId(btn, uniqueId);
-                mainLayout->addWidget(btn);
-                QObject::connect(btn, &QPushButton::clicked, this, &ZmqTrackingAlgorithm::btnClicked);
-            } else if (type == QChar('s')) {
-                const int min = widgetElems[2].toInt();
-                const int max = widgetElems[3].toInt();
-                const int defaultValue = widgetElems[4].toInt();
-                QLabel *txt = new QLabel(m_tools.get());
-                txt->setText(widgetElems[1]);
-                mainLayout->addWidget(txt);
-                QSlider *sld = new QSlider(Qt::Horizontal, m_tools.get());
-                setSenderId(sld, uniqueId);
-                sld->setMinimum(min);
-                sld->setMaximum(max);
-                sld->setValue(defaultValue);
-                mainLayout->addWidget(sld);
-                QObject::connect(sld, &QSlider::valueChanged, this, &ZmqTrackingAlgorithm::sldValueChanged);
-            } else {
-                // silently ignore
-            }
-        }
-    }
-    m_zmqMutex.unlock();
+    SendRequestWidgetsMessage message(m_tools);
+    m_process->send(message, m_events);
     return m_tools;
 }
 
@@ -201,124 +90,21 @@ void ZmqTrackingAlgorithm::keyPressEvent(QKeyEvent *) {
 
 }
 
-/**
- * @brief ZmqTrackingAlgorithm::listenToEvents
- * CAREFUL, this function is NOT THREADSAFE
- */
-void ZmqTrackingAlgorithm::listenToEvents() {
-    if (!m_isDead) {
-        QString event = recv_string(m_socket);
-
-        switch (zmq_errno()) {
-        case EAGAIN:
-            // if we timeout, we wont to notify the tracker..
-            m_isDead = true;
-            return;
-        }
-
-        while (event != EVENT_STOP_LISTENING) {
-            // handle event
-            if (event == EVENT_UPDATE) {
-                Q_EMIT update();
-            } else if (event == EVENT_FORCE_TRACKING) {
-                Q_EMIT forceTracking();
-            } else {
-                const QStringList eventParts = event.split(",");
-                if (eventParts[0] == EVENT_NOTIFY_GUI) {
-                    QString message = eventParts[1];
-                    // as the ',' and ';' characters are special symbols
-                    // for the zmq message transmission they get encoded
-                    // so they dont mess with the zmq message. Here we need
-                    // to restore them
-                    message = message.replace("%2C", ",");
-                    message = message.replace("%3B", ";");
-
-                    const size_t mtypeInt = eventParts[2].toInt();
-                    const MSGS::MTYPE mtype = MSGS::fromInt(mtypeInt);
-                    Q_EMIT notifyGUI(message.toStdString(), mtype);
-                } else if (eventParts[0] == EVENT_JUMP_TO_FRAME) {
-                    const size_t frame = eventParts[1].toInt();
-                    Q_EMIT jumpToFrame(frame);
-                } else if (eventParts[0] == EVENT_PLAY_PAUSE) {
-                    if (eventParts[1] == EVENT_MSG_FALSE) {
-                        Q_EMIT pausePlayback(false);
-                    } else {
-                        Q_EMIT pausePlayback(true);
-                    }
-                } else {
-                    assert(false);
-                }
-            }
-            event = recv_string(m_socket);
-        }
-    }
-}
-
 void ZmqTrackingAlgorithm::shutdown() {
-    std::cout << "try shutdown!" << std::endl;
-    m_zmqMutex.lock();
-    m_isDead = true;
-    send_string(m_socket, TYPE_SHUTDOWN, 0);
-    this->listenToEvents();
-    QThread::msleep(500);
-    m_zmqMutex.unlock();
-    m_zmqClient->kill();
-    m_zmqClient->waitForFinished(1000);
-    m_zmqMutex.unlock();
-    zmq_disconnect(m_socket, "172.0.0.1:5556");
-    zmq_close(m_socket);
-    zmq_ctx_term(m_context);
-    std::cout << "end shutdown!" << std::endl;
 }
 
 // == EVENTS ==
 
-void ZmqTrackingAlgorithm::btnClicked() {
-    if (m_isDead) {
-        return;
-    }
-    const QString widgetId = getSenderId(sender());
-    QString message;
-    message.append(WIDGET_EVENT_CLICK);
-    message.append(",");
-    message.append(widgetId);
-    m_zmqMutex.lock();
-    send_string(m_socket, TYPE_SEND_WIDGET_EVENT, ZMQ_SNDMORE);
-    send_string(m_socket, message, 0);
-    this->listenToEvents();
-    m_zmqMutex.unlock();
-}
-
-void ZmqTrackingAlgorithm::sldValueChanged(int value) {
-    if (m_isDead) {
-        return;
-    }
-    const QString widgetId = getSenderId(sender());
-    QString message;
-    message.append(WIDGET_EVENT_CHANGED);
-    message.append(",");
-    message.append(widgetId);
-    message.append(",");
-    message.append(QString::number(value));
-    m_zmqMutex.lock();
-    send_string(m_socket, TYPE_SEND_WIDGET_EVENT, ZMQ_SNDMORE);
-    send_string(m_socket, message, 0);
-    this->listenToEvents();
-    m_zmqMutex.unlock();
+void ZmqTrackingAlgorithm::btnClicked(const QString widgetId) {
+    SendButtonClickMessage message(widgetId);
+    m_process->send(message, m_events);
 }
 
-// == EVENTS end ==
-
-void ZmqTrackingAlgorithm::processError(QProcess::ProcessError error) {
-    const QString errorStr(m_zmqClient->readAllStandardError());
-    shutdown();
+void ZmqTrackingAlgorithm::sldValueChanged(const QString widgetId, int value) {
+    SendValueChangedMessage message(widgetId, value);
+    m_process->send(message, m_events);
 }
 
-void ZmqTrackingAlgorithm::processHasError() {
-    const QString error(m_zmqClient->readAllStandardError());
-    shutdown();
-
-}
 
 }
 }
diff --git a/biotracker/src/zmq/ZmqClientProcess.cpp b/biotracker/src/zmq/ZmqClientProcess.cpp
index c98d6bc1c7ebcccd53c720115b409b2c335e6422..94ac5c422b276c88f8dfa0c504f99cffe0e86345 100644
--- a/biotracker/src/zmq/ZmqClientProcess.cpp
+++ b/biotracker/src/zmq/ZmqClientProcess.cpp
@@ -1,10 +1,10 @@
-#include "zmq/ZmqClientProcess.h"
+#include "biotracker/zmq/ZmqClientProcess.h"
 
 #include <opencv/cv.hpp>
 #include <QProcess>
 #include <QString>
 
-#include "zmq/ZmqHelper.h"
+#include "biotracker/zmq/ZmqHelper.h"
 
 namespace BioTracker {
 namespace Core {
@@ -92,8 +92,17 @@ void ZmqClientProcess::send(GenericSendMessage &message, EventHandler &handler)
     m_zmqMutex.unlock();
 }
 
-void BioTracker::Core::Zmq::ZmqClientProcess::shutdown() {
+void ZmqClientProcess::shutdown() {
     isFree = true;
+    m_zmqMutex.lock();
+    send_string(SOCKET, TYPE_SHUTDOWN, 0);
+    EventHandler temp(this);
+    listenToEvents(temp);
+    m_zmqClient->kill();
+    m_zmqClient->waitForFinished(1000);
+    zmq_disconnect(SOCKET, "172.0.0.1:5556");
+    zmq_close(SOCKET);
+    m_zmqMutex.unlock();
 }
 
 // =========================================
@@ -120,7 +129,7 @@ void ZmqClientProcess::paintOverlay(SendPaintOverlayMessage &message, EventHandl
 }
 
 void ZmqClientProcess::requestTools(SendRequestWidgetsMessage &message, EventHandler &handler) {
-    ReceiveToolsWidgetMessage result(message);
+    ReceiveToolsWidgetMessage result(message, handler);
     sendMessage(message);
     listenToEvents(handler);
     requestResults(result);
@@ -153,7 +162,13 @@ void ZmqClientProcess::sendMessage(GenericSendMessage &message) {
             flag = ZMQ_SNDMORE;
         }
         ZmqMessage m = messageParts[i];
-        zmq_send(SOCKET, m.data, m.sizeInBytes, flag);
+
+        if (m.isText) {
+            send_string(SOCKET, m.text, flag);
+        } else { // send mat DATA
+            size_t sizeInBytes = m.mat.total() * m.mat.elemSize();
+            zmq_send(SOCKET, m.mat.data, sizeInBytes, flag);
+        }
     }
 }
 
@@ -170,7 +185,8 @@ void recvThatMat(cv::Mat &m) {
  * @param handler
  */
 void ZmqClientProcess::listenToEvents(EventHandler &handler) {
-
+    recvString func = &recvThisString;
+    handler.receive(func);
 }
 
 /**
@@ -178,18 +194,20 @@ void ZmqClientProcess::listenToEvents(EventHandler &handler) {
  * @param message
  */
 void ZmqClientProcess::requestResults(GenericReceiveMessage &message) {
-
+    recvString func = &recvThisString;
+    recvMat funcMat = &recvThatMat;
+    message.receive(func, funcMat);
 }
 
 // ===========================================
 // ===========================================
 
 void BioTracker::Core::Zmq::ZmqClientProcess::processBadError(QProcess::ProcessError error) {
-
+    // TODO implement error handling
 }
 
 void BioTracker::Core::Zmq::ZmqClientProcess::processError() {
-
+    // TODO implement error handling
 }
 
 }
diff --git a/biotracker/src/zmq/ZmqHelper.cpp b/biotracker/src/zmq/ZmqHelper.cpp
index 2978f5fb4bd390a2794f1259305877751f65ee9e..e4cb48419224bc8c3fdf85aba8eb697a617b2787 100644
--- a/biotracker/src/zmq/ZmqHelper.cpp
+++ b/biotracker/src/zmq/ZmqHelper.cpp
@@ -1,4 +1,4 @@
-#include "zmq/ZmqHelper.h"
+#include "biotracker/zmq/ZmqHelper.h"
 
 namespace BioTracker {
 namespace Core {
diff --git a/biotracker/src/zmq/ZmqInfoFile.cpp b/biotracker/src/zmq/ZmqInfoFile.cpp
index 9454e8197b7aef409e25d0a14d5f0a55ffbfecea..2d22047975297ef1c6a6538367c0c1e5ef692e93 100644
--- a/biotracker/src/zmq/ZmqInfoFile.cpp
+++ b/biotracker/src/zmq/ZmqInfoFile.cpp
@@ -1,8 +1,8 @@
-#include "zmq/ZmqInfoFile.h"
+#include "biotracker/zmq/ZmqInfoFile.h"
 
 #include <QFile>
 #include <QTextStream>
-#include "Exceptions.h"
+#include "biotracker/Exceptions.h"
 
 namespace BioTracker {
 namespace Core {
diff --git a/biotracker/src/zmq/ZmqMessageParser.cpp b/biotracker/src/zmq/ZmqMessageParser.cpp
index 7bc203ecf59a95a9c307ed983cdb18045d0b1cd3..e513ca9e47f3be1d5ae17173c701e4597a9b5ade 100644
--- a/biotracker/src/zmq/ZmqMessageParser.cpp
+++ b/biotracker/src/zmq/ZmqMessageParser.cpp
@@ -1,4 +1,4 @@
-#include "zmq/ZmqMessageParser.h"
+#include "biotracker/zmq/ZmqMessageParser.h"
 
 #include <QVBoxLayout>
 #include <QLabel>
@@ -9,22 +9,12 @@ namespace BioTracker {
 namespace Core {
 namespace Zmq {
 
-const QString TYPE_TRACK("0");
-const QString TYPE_PAINT("1");
-const QString TYPE_SHUTDOWN("2");
-const QString TYPE_PAINTOVERLAY("3");
-const QString TYPE_REQUEST_WIDGETS("4");
-const QString TYPE_SEND_WIDGET_EVENT("5");
-
-const QString WIDGET_EVENT_CLICK("0");
-const QString WIDGET_EVENT_CHANGED("1");
-
 // ================================
 // GenericSendMessage
 // ================================
 
-ZmqMessage GenericSendMessage::fromString(const QString &str) {
-    ZmqMessage m(str.toUtf8().constData(), str.size());
+ZmqMessage GenericSendMessage::fromString(const QString str) {
+    ZmqMessage m(str);
     return m;
 }
 
@@ -41,8 +31,7 @@ std::vector<ZmqMessage> SendTrackMessage::get() {
                    QString::number(m_frameNumber);
     message.push_back(fromString(data)); // #2
 
-    size_t sizeInBytes = m_frame.total() * m_frame.elemSize();
-    message.push_back(ZmqMessage(m_frame.data, sizeInBytes)); // #3
+    message.push_back(ZmqMessage(m_frame)); // #3
 
     return message;
 }
@@ -89,7 +78,6 @@ std::vector<ZmqMessage> SendRequestWidgetsMessage::get() {
 std::vector<ZmqMessage> SendButtonClickMessage::get() {
     std::vector<ZmqMessage> message;
     message.push_back(fromString(TYPE_SEND_WIDGET_EVENT));
-
     QString click;
     click.append(WIDGET_EVENT_CLICK);
     click.append(",");
@@ -169,60 +157,31 @@ void EventHandler::receive(BioTracker::Core::Zmq::recvString receiveStr) {
     }
 }
 
-// ================================
-// ZmqMessage
-// ================================
+inline QString getSenderId(QObject *obj) {
+    QWidget *w = qobject_cast<QWidget *>(obj);
+    return w->accessibleName();
+}
 
-QString ZmqMessage::toString() {
-    return QString::fromLocal8Bit(static_cast<const char *>(data), sizeInBytes);
+void EventHandler::btnClickedInternal() {
+    QWidget *w = qobject_cast<QWidget *>(sender());
+    const QString widgetId = w->accessibleName();
+    Q_EMIT btnClicked(widgetId);
+}
+
+void EventHandler::sldValueChangedInternal(int value) {
+    const QString widgetId = getSenderId(sender());
+    Q_EMIT sldValueChanged(widgetId, value);
 }
 
 // ================================
 // ReceivePaintMessage
 // ================================
 
-/*
-bool ReceivePaintMessage::receive(ZmqMessage m)
-{
-    const QString input = m.toString();
-    if (m_firstCall) {
-        m_firstCall = false;
-        if (input == "Y") {
-            return true;
-        }
-    } else if (m_secondCall) {
-        // receive matrix shape
-        QStringRef shape(&input);
-        QVector<QStringRef> shapeStr = shape.split(",");
-        m_w = shapeStr.at(0).toInt();
-        m_h = shapeStr.at(1).toInt();
-        m_type = shapeStr.at(2).toInt();
-        return true;
-    } else {
-        // receive matrix data
-        cv::Mat newMat(m_h, m_w, m_type, &m.data);
-        newMat.copyTo(m_mat);
-    }
-    return false;
-}
-*/
-
 void ReceivePaintMessage::receive(BioTracker::Core::Zmq::recvString receiveStr,
                                   BioTracker::Core::Zmq::recvMat recvMat) {
     QString input = receiveStr();
-    if (input != "Y") {
+    if (input == "Y") {
         recvMat(m_mat);
-        // receive matrix shape
-        /*input = receiveStr();
-        QStringRef shape(&input);
-        QVector<QStringRef> shapeStr = shape.split(",");
-        m_w = shapeStr.at(0).toInt();
-        m_h = shapeStr.at(1).toInt();
-        m_type = shapeStr.at(2).toInt();
-        return true;
-        // receive matrix data
-        cv::Mat newMat(m_h, m_w, m_type, &m.data);
-        newMat.copyTo(m_mat);*/
     }
 
 }
@@ -304,7 +263,7 @@ void ReceiveToolsWidgetMessage::receive(BioTracker::Core::Zmq::recvString receiv
                 btn->setText(widgetElems[1]);
                 btn->setAccessibleName(uniqueId);
                 mainLayout->addWidget(btn);
-                QObject::connect(btn, &QPushButton::clicked, m_buttonClickCallback);
+                QObject::connect(btn, &QPushButton::clicked, &m_events, &EventHandler::btnClickedInternal);
             } else if (type == QChar('s')) {
                 const int min = widgetElems[2].toInt();
                 const int max = widgetElems[3].toInt();
@@ -318,9 +277,10 @@ void ReceiveToolsWidgetMessage::receive(BioTracker::Core::Zmq::recvString receiv
                 sld->setMaximum(max);
                 sld->setValue(defaultValue);
                 mainLayout->addWidget(sld);
-                QObject::connect(sld, &QSlider::valueChanged, m_sliderChangedCallback);
+                QObject::connect(sld, &QSlider::valueChanged, &m_events, &EventHandler::sldValueChangedInternal);
             } else {
                 // silently ignore
+                // TODO: do something
             }
         }
     }
diff --git a/biotracker/src/zmq/ZmqProcessHandler.cpp b/biotracker/src/zmq/ZmqProcessHandler.cpp
index 71a0be184a095df6a5d78326e548ac9a02e8e6bc..76fdb64b63588330b9a70c463bbad3e5e13e58bd 100644
--- a/biotracker/src/zmq/ZmqProcessHandler.cpp
+++ b/biotracker/src/zmq/ZmqProcessHandler.cpp
@@ -1,33 +1,37 @@
-#include "zmq/ZmqProcessHandler.h"
+#include "biotracker/zmq/ZmqProcessHandler.h"
 
 namespace BioTracker {
 namespace Core {
 namespace Zmq {
 
-ZmqProcessHandler::ZmqProcessHandler(QObject *p, const ZmqInfoFile info, void *socket):
-    QObject(p),
-    m_socket(socket) {
+/**
+  CTOR
+ * @brief ZmqProcessHandler::ZmqProcessHandler
+ * @param parent
+ */
+ZmqProcessHandler::ZmqProcessHandler():
+    m_context(zmq_ctx_new()) {
 
 }
 
+/**
+  DTOR
+ * @brief ZmqProcessHandler::~ZmqProcessHandler
+ */
 ZmqProcessHandler::~ZmqProcessHandler() {
-
+    zmq_ctx_term(m_context);
 }
 
-void ZmqProcessHandler::stop() {
-
-}
-
-void ZmqProcessHandler::start() {
-
-}
-
-void ZmqProcessHandler::processBadError(QProcess::ProcessError error) {
-
-}
+std::shared_ptr<ZmqClientProcess> ZmqProcessHandler::startProcess(ZmqInfoFile &info) {
+    if (m_currentProcess) {
+        m_currentProcess->shutdown();
+        m_currentProcess.reset();
+    }
 
-void ZmqProcessHandler::processError() {
+    void *socket = zmq_socket(m_context, ZMQ_PAIR);
+    m_currentProcess = std::make_shared<ZmqClientProcess>(info, std::move(socket));
 
+    return m_currentProcess;
 }
 
 
diff --git a/biotracker/zmq/ZmqClientProcess.h b/biotracker/zmq/ZmqClientProcess.h
index 0ef49b975570c936de9eec9cefcef2117d858b11..30a25e2fa032c5f615127e37d1a34f2d749ae510 100644
--- a/biotracker/zmq/ZmqClientProcess.h
+++ b/biotracker/zmq/ZmqClientProcess.h
@@ -7,8 +7,8 @@
 #include <QPoint>
 #include <zmq.h>
 #include <opencv2/opencv.hpp>
-#include "zmq/ZmqMessageParser.h"
-#include "zmq/ZmqInfoFile.h"
+#include "biotracker/zmq/ZmqMessageParser.h"
+#include "biotracker/zmq/ZmqInfoFile.h"
 
 namespace BioTracker {
 namespace Core {
diff --git a/biotracker/zmq/ZmqHelper.h b/biotracker/zmq/ZmqHelper.h
index d47b9d71beb73c2e72d6952b1422d322be0f00f1..c64e74e256ed7acc2a7b248ddc9d560173a047c2 100644
--- a/biotracker/zmq/ZmqHelper.h
+++ b/biotracker/zmq/ZmqHelper.h
@@ -80,47 +80,6 @@ inline void send_mat(void *socket, const cv::Mat &mat, const size_t frameNbr) {
     zmq_send(socket, mat.data, sizeInBytes, 0);
 }
 
-/*
-QColor getColor(const QStringRef content) {
-    QVector<QStringRef> colorStr = content.split(",");
-    const int r = colorStr.at(0).toInt();
-    const int g = colorStr.at(1).toInt();
-    const int b = colorStr.at(2).toInt();
-    const int a = colorStr.at(3).toInt();
-    QColor color(r, g, b, a);
-    return color;
-}
-
-QRect getRect(const QStringRef content) {
-    QVector<QStringRef> colorStr = content.split(",");
-    const int x = colorStr.at(0).toInt();
-    const int y = colorStr.at(1).toInt();
-    const int w = colorStr.at(2).toInt();
-    const int h = colorStr.at(3).toInt();
-    QRect rect(x, y, w, h);
-    return rect;
-}
-
-void recv_QPainter(void *socket, QPainter *p) {
-    QString paintBatch = recv_string(socket);
-    if (paintBatch.length() > 0) {
-        QStringList batch = paintBatch.split(";");
-        for (int i = 0; i < batch.size(); ++i) {
-            const QString paintOperation = batch.at(i);
-            int start = 2;
-            int length = paintOperation.size() - 3;
-            QStringRef content(&paintOperation, start, length);
-            if (paintOperation.startsWith("p")) {
-                p->setPen(getColor(content));
-            } else if (paintOperation.startsWith("b")) {
-                p->setBrush(getColor(content));
-            } else if (paintOperation.startsWith("r")) {
-                p->drawRect(getRect(content));
-            }
-        }
-    }
-}
-*/
 }
 }
 }
diff --git a/biotracker/zmq/ZmqMessageParser.h b/biotracker/zmq/ZmqMessageParser.h
index 80ac9bcc04f21831589db614514636f438147496..a6d7c9182ee55bbe10696907313ac6aff513c6f4 100644
--- a/biotracker/zmq/ZmqMessageParser.h
+++ b/biotracker/zmq/ZmqMessageParser.h
@@ -10,25 +10,72 @@
 #include <zmq.h>
 #include <opencv2/opencv.hpp>
 #include <QProcess>
-#include "TrackingAlgorithm.h"
-#include "zmq/ZmqInfoFile.h"
-#include "settings/Messages.h"
+#include "biotracker/TrackingAlgorithm.h"
+#include "biotracker/zmq/ZmqInfoFile.h"
+#include "biotracker/settings/Messages.h"
 
 namespace BioTracker {
 namespace Core {
 namespace Zmq {
 
+const QString TYPE_TRACK("0");
+const QString TYPE_PAINT("1");
+const QString TYPE_SHUTDOWN("2");
+const QString TYPE_PAINTOVERLAY("3");
+const QString TYPE_REQUEST_WIDGETS("4");
+const QString TYPE_SEND_WIDGET_EVENT("5");
+
+const QString WIDGET_EVENT_CLICK("0");
+const QString WIDGET_EVENT_CHANGED("1");
+
+
+const cv::Mat DEFAULT_1x1(1,1, CV_8UC3);
+
+// TODO solve this more elegant with polymorphsm
 class ZmqMessage {
   public:
 
-    ZmqMessage(const void *d, int s):
-        data(d),
-        sizeInBytes(s) {}
+    ZmqMessage(QString str):
+        isText(true),
+        text(str),
+        mat(DEFAULT_1x1) {
+    }
+    ZmqMessage(const cv::Mat &m):
+        isText(false),
+        mat(m) {}
+
+    const bool isText;
+    const QString text;
+    const cv::Mat &mat;
+};
+
+typedef QString(*recvString)();
+typedef void (*recvMat)(cv::Mat &mat);
+
+// ======================================
+// EVENT HANDLER
+// ======================================
+
+class EventHandler : public QObject {
+    Q_OBJECT
+  public:
+    EventHandler(QObject *p): QObject(p) {}
+    void receive(recvString receiveStr);
+  Q_SIGNALS:
+    void notifyGUI(std::string, MSGS::MTYPE type = MSGS::MTYPE::NOTIFICATION);
+    void update();
+    // cv::Mat requestCurrentScreen();
+    void forceTracking();
+    //void registerViews(const std::vector<View> views);
+    void pausePlayback(bool paused);
+    void jumpToFrame(int frameNumber);
 
-    const void *data;
-    int sizeInBytes;
+    void btnClicked(const QString widgetId);
+    void sldValueChanged(const QString widgetId, int value);
+  public Q_SLOTS:
+    void btnClickedInternal();
+    void sldValueChangedInternal(int value);
 
-    QString toString();
 };
 
 // ======================================
@@ -45,10 +92,6 @@ enum MessageType {
     ValueChanged
 };
 
-typedef QString(*recvString)();
-typedef void (*recvMat)(cv::Mat &mat);
-
-
 class GenericSendMessage {
   public:
     GenericSendMessage(const MessageType t): type(t) {}
@@ -63,7 +106,7 @@ class GenericSendMessage {
     const MessageType type;
 
   protected:
-    ZmqMessage fromString(const QString &str);
+    ZmqMessage fromString(const QString str);
 };
 
 // ======================================
@@ -181,36 +224,28 @@ class ReceiveQPainterMessage: public GenericReceiveMessage {
 // REQUESTWIDGETS
 // ======================================
 
-typedef void (*ButtonClickCallback)();
-typedef void (*SliderChangedCallback)(int value);
-
 class SendRequestWidgetsMessage: public GenericSendMessage {
   public:
-    SendRequestWidgetsMessage(std::shared_ptr<QWidget> tools,
-                              ButtonClickCallback button, SliderChangedCallback slider):
+    SendRequestWidgetsMessage(std::shared_ptr<QWidget> tools):
         GenericSendMessage(RequestTools),
-        m_tools(tools), m_button(button), m_slider(slider) {}
+        m_tools(tools) {}
     std::vector<ZmqMessage>get() override;
 
     std::shared_ptr<QWidget> m_tools;
-    ButtonClickCallback m_button;
-    SliderChangedCallback m_slider;
 };
 
 // ======================================
 
 class ReceiveToolsWidgetMessage: public GenericReceiveMessage {
   public:
-    ReceiveToolsWidgetMessage(SendRequestWidgetsMessage &m):
-        m_tools(m.m_tools), m_buttonClickCallback(m.m_button),
-        m_sliderChangedCallback(m.m_slider) {}
+    ReceiveToolsWidgetMessage(SendRequestWidgetsMessage &m, EventHandler &evt):
+        m_tools(m.m_tools), m_events(evt) {}
 
     void receive(recvString receiveStr, recvMat recvMat) override;
 
   private:
     std::shared_ptr<QWidget> m_tools;
-    ButtonClickCallback m_buttonClickCallback;
-    SliderChangedCallback m_sliderChangedCallback;
+    EventHandler &m_events;
 };
 
 // ======================================
@@ -242,25 +277,6 @@ class SendValueChangedMessage: public GenericSendMessage {
     const int m_value;
 };
 
-// ======================================
-// EVENT HANDLER
-// ======================================
-
-class EventHandler : public QObject {
-    Q_OBJECT
-  public:
-    void receive(recvString receiveStr);
-  Q_SIGNALS:
-    void notifyGUI(std::string, MSGS::MTYPE type = MSGS::MTYPE::NOTIFICATION);
-    void update();
-    // cv::Mat requestCurrentScreen();
-    void forceTracking();
-    //void registerViews(const std::vector<View> views);
-    void pausePlayback(bool paused);
-    void jumpToFrame(int frameNumber);
-
-};
-
 
 }
 }
diff --git a/biotracker/zmq/ZmqProcessHandler.h b/biotracker/zmq/ZmqProcessHandler.h
index 521011224fc16faf1fd1b5b67c3c87eeda2127b1..4a522c526fe8007debe00f0941a8eecf65aafbe7 100644
--- a/biotracker/zmq/ZmqProcessHandler.h
+++ b/biotracker/zmq/ZmqProcessHandler.h
@@ -10,7 +10,9 @@
 #include <zmq.h>
 #include <opencv2/opencv.hpp>
 #include <QProcess>
-#include "zmq/ZmqInfoFile.h"
+#include "ZmqInfoFile.h"
+#include "ZmqClientProcess.h"
+#include "biotracker/util/singleton.h"
 
 namespace BioTracker {
 namespace Core {
@@ -19,29 +21,19 @@ namespace Zmq {
 /**
  * @brief The ZmqProcessHandler class
  */
-class ZmqProcessHandler : public QObject {
+class ZmqProcessHandler : public QObject, public Util::Singleton<ZmqProcessHandler> {
   public:
     Q_OBJECT
   public:
-    ZmqProcessHandler(QObject *parent, const ZmqInfoFile info, void *socket);
+    ZmqProcessHandler();
     ~ZmqProcessHandler();
 
-    void stop();
-
-    void start();
-
-  Q_SIGNALS:
-    void onError(std::string errorMessage);
-
-  private Q_SLOTS:
-    void processBadError(QProcess::ProcessError error);
-    void processError();
+    std::shared_ptr<ZmqClientProcess> startProcess(ZmqInfoFile &info);
 
   private:
-    void *m_socket;
+    void *m_context;
     std::mutex m_zmqMutex;
-    std::unique_ptr<QProcess> m_zmqClient;
-
+    std::shared_ptr<ZmqClientProcess> m_currentProcess;
 };
 
 }