#include "vnc_server_manager.h" #include #include #include namespace LtsProjectionWorkstation { VncServerManager::VncServerManager(LOGGER_T &logger, QObject *parent) : QObject(parent) , m_logger(logger) { } VncServerManager::~VncServerManager() { stopScreens(); } QList sortScreen(const QList &screens) { auto ret(screens); auto doSortScreens = [](const QScreen *s1, const QScreen *s2) -> bool { const auto tl1 = s1->geometry().topLeft(); const auto tl2 = s2->geometry().topLeft(); if (tl1.y() > tl2.y()) return true; if (tl1.y() < tl2.y()) return false; return tl1.x() < tl2.x(); }; std::sort(ret.begin(), ret.end(), doSortScreens); return ret; } bool VncServerManager::init(const QList &screens) { killScreens(); createPwdFile(); const auto sortedScreens = sortScreen(screens); DEBUG_LOG(m_logger) << "Setup VNCScreens with " << screens.size() << " screens"; int count = 1; static constexpr char VNC_START_ARGS[] = "-rfbauth,%1/.vnc/passwd,-clip,%2x%3+%4+%5,-loop100,-forever,-display,:0,-threads,-noxdamage"; for (QScreen *screen : sortedScreens) { VncScreen vncScreen; vncScreen.geometry = screen->geometry(); vncScreen.name = QStringLiteral("Display%1").arg(count); vncScreen.proc = new QProcess(this); QString startArgs = QString::fromLatin1(VNC_START_ARGS).arg(QDir::home().absolutePath()) .arg(screen->geometry().width()).arg(screen->geometry().height()) .arg(screen->geometry().x()).arg(screen->geometry().y()); vncScreen.proc->setProgram(QStringLiteral("x11vnc")); vncScreen.proc->setArguments(startArgs.split(QLatin1Char(','))); NOTICE_LOG(m_logger) << "Started VNC for Screen " << count << " with geometry " << screen->geometry().width() << "," << screen->geometry().height() << "+" << screen->geometry().x() << "+" << screen->geometry().y(); m_vncScreens.push_back(vncScreen); count++; } DEBUG_LOG(m_logger) << m_vncScreens.size() << " VNCScreen(s) created - Setup completed."; return true; } void VncServerManager::startScreens() { DEBUG_LOG(m_logger) << "Starting " << m_vncScreens.size() << " VNCScreen(s) ... "; for (const VncScreen &s : qAsConst(m_vncScreens)) { connect(s.proc, &QProcess::readyReadStandardOutput, this, &VncServerManager::slotReadStandardOutput, Qt::UniqueConnection); connect(s.proc, &QProcess::errorOccurred, this, &VncServerManager::slotErrorOccured, Qt::UniqueConnection); s.proc->start(); } for (const VncScreen &s : qAsConst(m_vncScreens)) { if (!s.proc->waitForStarted(2000)) ERROR_LOG(m_logger) << "Can not start process '" << s.proc->program() << "': " << s.proc->errorString(); } DEBUG_LOG(m_logger) << "Done"; } void VncServerManager::stopScreens() { DEBUG_LOG(m_logger) << "Stopping " << m_vncScreens.size() << " VNCScreen(s) ..."; for (const VncScreen &s : qAsConst(m_vncScreens)) { s.proc->disconnect(this); s.proc->terminate(); } for (const VncScreen &s : qAsConst(m_vncScreens)) { if (!s.proc->waitForFinished(2000)) s.proc->kill(); } DEBUG_LOG(m_logger) << "Done"; } void VncServerManager::killScreens() { DEBUG_LOG(m_logger) << "Killing all exisiting x11vnc processes ..."; SingleShotProcess ssp(QStringLiteral("killall x11vnc")); ssp.execute(); DEBUG_LOG(m_logger) << "Done"; } void VncServerManager::createPwdFile() { DEBUG_LOG(m_logger) << "(Re)creating x11vnc password-file ..."; SingleShotProcess ssp(QStringLiteral("x11vnc -storepasswd ctc11de %1/.vnc/passwd") .arg(QDir::home().absolutePath())); ssp.execute(); DEBUG_LOG(m_logger) << "Done"; } void VncServerManager::slotReadStandardOutput() { QProcess *p = qobject_cast(QObject::sender()); if (!p) return; QString stdOut = QString::fromLocal8Bit(p->readAllStandardOutput()); QRegularExpressionMatch match = QRegularExpression(QStringLiteral("PORT=(.*?)\\s")).match(stdOut); if (!match.hasMatch()) { WARNING_LOG(m_logger) << "Could not retrieve port information from stdout of " << p->program(); return; } const quint16 port = match.capturedRef(1).toInt(); if (port == 0) return; for (VncScreen &screen : m_vncScreens) { if (screen.proc != p) continue; screen.port = port; disconnect(screen.proc, &QProcess::readyReadStandardOutput, nullptr, nullptr); break; } } void VncServerManager::slotErrorOccured() { QProcess *p = qobject_cast(QObject::sender()); if (p) ERROR_LOG(m_logger) << p->errorString(); } SingleShotProcess::SingleShotProcess(const QString &cmd, bool startImmediatly) : m_cmd(cmd) { if (startImmediatly) execute(); } bool SingleShotProcess::execute() { m_process.start(m_cmd); return m_process.waitForFinished(); } }