From 74d42e667d4094844929c49c0670c752ebc57cc3 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 17 Jul 2018 17:33:19 +0200 Subject: [client] Rewrite thread sync between VNC worker and VNC window --- src/client/vnc/vncthread.cpp | 82 ++++++++++++++++++++------------------------ src/client/vnc/vncthread.h | 15 ++++---- src/client/vnc/vncwindow.cpp | 28 ++++++++------- src/client/vnc/vncwindow.h | 3 ++ 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/src/client/vnc/vncthread.cpp b/src/client/vnc/vncthread.cpp index cafdace..dcc61d0 100644 --- a/src/client/vnc/vncthread.cpp +++ b/src/client/vnc/vncthread.cpp @@ -44,7 +44,7 @@ static int gcd(int a, int b) * @param quality The desired quality level for the VNC stream */ VncThread::VncThread(QString host, int port, QString passwd, int quality) : - QThread(), _frameBuffer(NULL), _painter(NULL), _hasNewLocalSize(false), _run(true) + QThread(), _frameBuffer(NULL), _run(true), _started(false) { _srcStepX = _srcStepY = _dstStepX = _dstStepY = 0; _host = host; @@ -60,7 +60,7 @@ VncThread::~VncThread() { qDebug("VNC worker destructor called."); Q_ASSERT(_run == false); - if (_frameBuffer) + if (_frameBuffer != NULL) delete[] _frameBuffer; if (_client != NULL) { if (_client->sock != -1) @@ -69,8 +69,6 @@ VncThread::~VncThread() _client->frameBuffer = NULL; rfbClientCleanup(_client); } - if (_painter != NULL) - delete _painter; } /** @@ -85,9 +83,9 @@ VncThread::~VncThread() */ void VncThread::calcScaling() { - if (_localSize.isEmpty() || _localSize.width() == 0 || _localSize.height() == 0) + if (_localSize.isEmpty()) return; - if (_clientSize.isEmpty() || _clientSize.width() == 0 || _clientSize.height() == 0) + if (_clientSize.isEmpty()) return; const int gcdX = gcd(_localSize.width(), _clientSize.width()); const int gcdY = gcd(_localSize.height(), _clientSize.height()); @@ -107,16 +105,9 @@ void VncThread::calcScaling() * * @param size The new size of the viewer window */ -void VncThread::setTargetSize(const QSize size) +void VncThread::setTargetBuffer(QSharedPointer &buffer) { - if (_localSize == size) - return; - qDebug() << "Setting target size to " << size; - { - QMutexLocker lock(&_mutex); - _newLocalSize = size; - _hasNewLocalSize = true; - } + _imgScaled = buffer; } /** @@ -175,7 +166,6 @@ void VncThread::run() // Main VNC event loop if (_run) { _connected = true; - emit projectionStarted(); } while (_run) { const int i = WaitForMessage(_client, 100 * 1000); // wait 100ms for message. returns -1 on error/disconnect, 0 if nothing happened, 1 if new data arrived @@ -183,17 +173,6 @@ void VncThread::run() break; if (i > 0 && !HandleRFBServerMessage(_client)) break; - - if (_hasNewLocalSize) { - QMutexLocker lock(&_mutex); - _hasNewLocalSize = false; - _localSize = _newLocalSize; - if (_painter != NULL) - delete _painter; - _imgScaled = QImage(_localSize, QImage::Format_RGB32); - _painter = new QPainter(&_imgScaled); - this->calcScaling(); - } } } @@ -226,8 +205,18 @@ const QString VncThread::getDesktopName() const * @param w width of the area in the framebuffer that changed * @param h height of the area in the framebuffer that changed */ -void VncThread::processImageUpdate(const int x, const int y, const int w, const int h) +void VncThread::processImageUpdate(int x, int y, int w, int h) { + QSharedPointer buffer = _imgScaled; + QPainter painter(buffer.data()); + if (buffer->size() != _localSize) { + _localSize = buffer->size(); + this->calcScaling(); + x = 0; + y = 0; + w = _img.width(); + h = _img.height(); + } if (_srcStepX > 1 || _srcStepY > 1) { // Scaling is required as vnc server and client are using different resolutions // Calc section offsets first @@ -241,24 +230,24 @@ void VncThread::processImageUpdate(const int x, const int y, const int w, const const int srcW = endX * _srcStepX - srcX; const int srcH = endY * _srcStepY - srcY; // Pixel offsets for destination - const int dstX = startX * _dstStepX; - const int dstY = startY * _dstStepY; - const int dstW = endX * _dstStepX - dstX; - const int dstH = endY * _dstStepY - dstY; + x = startX * _dstStepX; + y = startY * _dstStepY; + w = endX * _dstStepX - x; + h = endY * _dstStepY - y; // Rescale - { - QMutexLocker lock(&_mutex); - if (_painter != NULL) { - QImage scaled( - _img.copy(srcX, srcY, srcW, srcH).scaled(dstW, dstH, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - _painter->drawImage(dstX, dstY, scaled, 0, 0, dstW, dstH); - } - } - emit imageUpdated(dstX, dstY, dstW, dstH); + QImage scaled( + _img.copy(srcX, srcY, srcW, srcH).scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); + painter.drawImage(x, y, scaled, 0, 0, w, h); } else { // Same resolution, nothing to do - emit imageUpdated(x, y, w, h); + painter.drawImage(x, y, _img, x, y, w, h); } + emit imageUpdated(x, y, w, h); +} + +void VncThread::emitStarted() +{ + emit projectionStarted(); } // *** callback stuff *** @@ -290,9 +279,7 @@ rfbBool VncThread::frameBufferHandler(rfbClient *client) const int size = width * height * (depth / 8); qDebug("[%s] Remote desktop: %ix%ix%i", t->metaObject()->className(), width, height, depth); - QMutexLocker lock(&(t->_mutex)); - - if (t->_frameBuffer) + if (t->_frameBuffer != NULL) delete[] t->_frameBuffer; t->_frameBuffer = new uint8_t[size]; @@ -341,6 +328,11 @@ rfbBool VncThread::frameBufferHandler(rfbClient *client) SendFramebufferUpdateRequest(client, 0, 0, width, height, false); + if (!t->_started) { + t->_started = true; + t->emitStarted(); + } + return true; } diff --git a/src/client/vnc/vncthread.h b/src/client/vnc/vncthread.h index afdb92a..38f5e17 100644 --- a/src/client/vnc/vncthread.h +++ b/src/client/vnc/vncthread.h @@ -17,6 +17,7 @@ #include #include #include +#include class QPainter; @@ -45,23 +46,20 @@ private: QString _passwd; int _quality; - QPainter *_painter; QImage _img; - QImage _imgScaled; + QSharedPointer _imgScaled; QSize _clientSize; QSize _localSize; - QMutex _mutex; - - QSize _newLocalSize; - volatile bool _hasNewLocalSize; int _srcStepX, _srcStepY, _dstStepX, _dstStepY; volatile bool _connected; volatile bool _run; + bool _started; void calcScaling(); - void processImageUpdate(const int x, const int y, const int w, const int h); + void processImageUpdate(int x, int y, int w, int h); + void emitStarted(); // Callbacks for rfb lib. make them class members so the callbacks can access private members of the class. @@ -73,12 +71,11 @@ public: VncThread(QString host, int port, QString passwd, int quality); ~VncThread(); - const QImage& getImage() const { if (_srcStepX > 1 || _srcStepY > 1) return _imgScaled; return _img; } const QSize& getSourceSize() const { return _clientSize; } const QString getDesktopName() const; bool isConnected() { return _connected; } void stop() { _run = false; } - void setTargetSize(const QSize size); + void setTargetBuffer(QSharedPointer &buffer); void run(); int const static HIGH = 0; diff --git a/src/client/vnc/vncwindow.cpp b/src/client/vnc/vncwindow.cpp index 3ad75e8..4976bbd 100644 --- a/src/client/vnc/vncwindow.cpp +++ b/src/client/vnc/vncwindow.cpp @@ -22,7 +22,8 @@ #include VncWindow::VncWindow(QWidget *parent) : - QWidget(parent), _vncWorker(NULL), _viewOnly(true), _multiScreen(false), _clientId(0), _redrawTimer(0), _tcpTimeoutTimer(0) + QWidget(parent), _vncWorker(NULL), _viewOnly(true), _multiScreen(false), _clientId(0), _redrawTimer(0), _tcpTimeoutTimer(0), + _image(new QImage) { QTimer *upper = new QTimer(this); connect(upper, SIGNAL(timeout()), this, SLOT(timer_moveToTop())); @@ -85,7 +86,7 @@ void VncWindow::draw(const int x, const int y, const int w, const int h) if (_vncWorker == NULL) return; QPainter painter(this); - painter.drawImage(x, y, _vncWorker->getImage(), x, y, w, h); + painter.drawImage(x, y, *_image, x, y, w, h); //painter.drawRect(x,y,w,h); // for debugging updated area } @@ -125,7 +126,7 @@ void VncWindow::open(const QString& host, int port, const QString& passwd, bool QSize size; if (fullscreen) { - setWindowFlags(Qt::WindowStaysOnTopHint); // | Qt::X11BypassWindowManagerHint); <- better, but window won't get any keyboard input + setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool); // | Qt::X11BypassWindowManagerHint); <- better, but window won't get any keyboard input // Show projection on rightmost screen QDesktopWidget *desktop = QApplication::desktop(); int ns = desktop->numScreens(); @@ -137,9 +138,11 @@ void VncWindow::open(const QString& host, int port, const QString& passwd, bool } } _multiScreen = ns > 1; + qDebug() << "Spawning at" << best; size = best.size(); setGeometry(best); - showFullScreen(); + move(best.topLeft()); + //showFullScreen(); activateWindow(); raise(); } else { @@ -150,7 +153,7 @@ void VncWindow::open(const QString& host, int port, const QString& passwd, bool this->repaint(); this->show(); - _vncWorker->setTargetSize(size); + _vncWorker->setTargetBuffer(_image); _tcpTimeoutTimer = startTimer(10000); _vncWorker->start(QThread::LowPriority); @@ -204,8 +207,7 @@ void VncWindow::onProjectionStarted() _tcpTimeoutTimer = 0; } emit running(true, _clientId); - _redrawTimer = startTimer(3000); - _vncWorker->setTargetSize(this->size()); + _redrawTimer = startTimer(500); } /** @@ -246,8 +248,7 @@ void VncWindow::timerEvent(QTimerEvent *event) if (event->timerId() == _redrawTimer) { killTimer(_redrawTimer); _redrawTimer = 0; - if (this->isVisible()) - this->repaint(); + this->update(); } else if (event->timerId() == _tcpTimeoutTimer) { killTimer(_tcpTimeoutTimer); _tcpTimeoutTimer = 0; @@ -293,10 +294,13 @@ void VncWindow::paintEvent(QPaintEvent *event) */ void VncWindow::resizeEvent(QResizeEvent* event) { + const QSize size = event->size(); + if (size != _image->size()) { + _image = QSharedPointer(new QImage(size, QImage::Format_RGB32)); + } if (_vncWorker != NULL) { - _vncWorker->setTargetSize(event->size()); + _vncWorker->setTargetBuffer(_image); } - this->repaint(); } /** @@ -304,7 +308,7 @@ void VncWindow::resizeEvent(QResizeEvent* event) */ void VncWindow::keyReleaseEvent(QKeyEvent* event) { - if (event->modifiers() == 0 && event->key() == Qt::Key_Escape && !clientApp->isConnectedToLocalManager()) { + if (event->modifiers() == 0 && event->key() == Qt::Key_Escape && clientApp->isConnectedToLocalManager()) { this->close(); } else { QWidget::keyReleaseEvent(event); diff --git a/src/client/vnc/vncwindow.h b/src/client/vnc/vncwindow.h index df37513..cdcf51f 100644 --- a/src/client/vnc/vncwindow.h +++ b/src/client/vnc/vncwindow.h @@ -15,6 +15,8 @@ #define CLIENTVNCVIEWER_H_ #include +#include +#include class VncThread; class QPainter; @@ -55,6 +57,7 @@ private: int _redrawTimer; int _tcpTimeoutTimer; QPixmap _remoteThumb; + QSharedPointer _image; void draw(const int x, const int y, const int w, const int h); void terminateVncThread(); -- cgit v1.2.3-55-g7522