Index: rdp/rdpview.cpp =================================================================== --- rdp/rdpview.cpp +++ rdp/rdpview.cpp @@ -160,21 +160,19 @@ QStringList arguments; - int width, height; + QSize size; + const auto dpr = devicePixelRatioF(); if (m_hostPreferences->width() > 0) { - width = m_hostPreferences->width(); - height = m_hostPreferences->height(); + size = QSize(m_hostPreferences->width(), m_hostPreferences->height()); } else { - width = this->parentWidget()->size().width(); - height = this->parentWidget()->size().height(); + size = this->parentWidget()->size() * dpr; } - m_containerWidget->setFixedWidth(width); - m_containerWidget->setFixedHeight(height); - setMaximumSize(width, height); + m_containerWidget->setFixedSize(size / dpr); + setMaximumSize(size / dpr); if (versionOutput.contains(QLatin1String(" 1.0"))) { qCDebug(KRDC) << "Use FreeRDP 1.0 compatible arguments"; - arguments << QStringLiteral("-g") << QString::number(width) + QLatin1Char('x') + QString::number(height); + arguments << QStringLiteral("-g") << QString::number(size.width()) + QLatin1Char('x') + QString::number(size.height()); arguments << QStringLiteral("-k") << keymapToXfreerdp(m_hostPreferences->keyboardLayout()); @@ -267,8 +265,8 @@ qCDebug(KRDC) << "Use FreeRDP 1.1+ compatible arguments"; arguments << QStringLiteral("-decorations"); - arguments << QStringLiteral("/w:") + QString::number(width); - arguments << QStringLiteral("/h:") + QString::number(height); + arguments << QStringLiteral("/w:") + QString::number(size.width()); + arguments << QStringLiteral("/h:") + QString::number(size.height()); arguments << QStringLiteral("/kbd:") + keymapToXfreerdp(m_hostPreferences->keyboardLayout()); Index: vnc/vncclientthread.h =================================================================== --- vnc/vncclientthread.h +++ vnc/vncclientthread.h @@ -111,6 +111,7 @@ void setHost(const QString &host); void setPort(int port); void setQuality(RemoteView::Quality quality); + void setDevicePixelRatio(qreal dpr); void setPassword(const QString &password) { m_password = password; } @@ -180,6 +181,7 @@ int m_port; QMutex mutex; RemoteView::Quality m_quality; + qreal m_devicePixelRatio; ColorDepth m_colorDepth; QQueue m_eventQueue; //color table for 8bit indexed colors Index: vnc/vncclientthread.cpp =================================================================== --- vnc/vncclientthread.cpp +++ vnc/vncclientthread.cpp @@ -209,6 +209,7 @@ return; // sending data to a stopped thread is not a good idea } + img.setDevicePixelRatio(m_devicePixelRatio); setImage(img); emitUpdated(x, y, w, h); @@ -324,6 +325,7 @@ , frameBuffer(nullptr) , cl(nullptr) , m_stopped(false) + , m_devicePixelRatio(1.0) { // We choose a small value for interval...after all if the connection is // supposed to sustain a VNC session, a reasonably frequent ping should @@ -397,6 +399,11 @@ } } +void VncClientThread::setDevicePixelRatio(qreal dpr) +{ + m_devicePixelRatio = dpr; +} + void VncClientThread::setColorDepth(ColorDepth colorDepth) { m_colorDepth= colorDepth; Index: vnc/vncview.cpp =================================================================== --- vnc/vncview.cpp +++ vnc/vncview.cpp @@ -115,7 +115,7 @@ QSize VncView::framebufferSize() { - return m_frame.size(); + return m_frame.size() / devicePixelRatioF(); } QSize VncView::sizeHint() const @@ -134,8 +134,9 @@ qCDebug(KRDC) << w << h; if (m_scale) { - m_verticalFactor = (qreal) h / m_frame.height(); - m_horizontalFactor = (qreal) w / m_frame.width(); + const QSize frameSize = m_frame.size() / m_frame.devicePixelRatio(); + m_verticalFactor = (qreal) h / frameSize.height(); + m_horizontalFactor = (qreal) w / frameSize.width(); #ifndef QTONLY if (Settings::keepAspectRatio()) { @@ -145,8 +146,8 @@ m_verticalFactor = m_horizontalFactor = qMin(m_verticalFactor, m_horizontalFactor); #endif - const qreal newW = m_frame.width() * m_horizontalFactor; - const qreal newH = m_frame.height() * m_verticalFactor; + const qreal newW = frameSize.width() * m_horizontalFactor; + const qreal newH = frameSize.height() * m_verticalFactor; setMaximumSize(newW, newH); //This is a hack to force Qt to center the view in the scroll area resize(newW, newH); } @@ -243,6 +244,7 @@ #endif vncThread.setQuality(quality); + vncThread.setDevicePixelRatio(devicePixelRatioF()); // set local cursor on by default because low quality mostly means slow internet connection if (quality == RemoteView::Low) { @@ -438,8 +440,9 @@ if (m_scale) { #ifndef QTONLY qCDebug(KRDC) << "Setting initial size w:" <width() << " h:" << m_hostPreferences->height(); - emit framebufferSizeChanged(m_hostPreferences->width(), m_hostPreferences->height()); - scaleResize(m_hostPreferences->width(), m_hostPreferences->height()); + QSize frameSize = QSize(m_hostPreferences->width(), m_hostPreferences->height()) / devicePixelRatioF(); + emit framebufferSizeChanged(frameSize.width(), frameSize.height()); + scaleResize(frameSize.width(), frameSize.height()); qCDebug(KRDC) << "m_frame.size():" << m_frame.size() << "size()" << size(); #else //TODO: qtonly alternative @@ -460,22 +463,24 @@ #endif } - if ((y == 0 && x == 0) && (m_frame.size() != size())) { + const QSize frameSize = m_frame.size() / m_frame.devicePixelRatio(); + if ((y == 0 && x == 0) && (frameSize != size())) { qCDebug(KRDC) << "Updating framebuffer size"; if (m_scale) { setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); if (parentWidget()) scaleResize(parentWidget()->width(), parentWidget()->height()); } else { qCDebug(KRDC) << "Resizing: " << m_frame.width() << m_frame.height(); - resize(m_frame.width(), m_frame.height()); - setMaximumSize(m_frame.width(), m_frame.height()); //This is a hack to force Qt to center the view in the scroll area - setMinimumSize(m_frame.width(), m_frame.height()); - emit framebufferSizeChanged(m_frame.width(), m_frame.height()); + resize(frameSize); + setMaximumSize(frameSize); //This is a hack to force Qt to center the view in the scroll area + setMinimumSize(frameSize); + emit framebufferSizeChanged(frameSize.width(), frameSize.height()); } } - repaint(QRectF(x * m_horizontalFactor, y * m_verticalFactor, w * m_horizontalFactor, h * m_verticalFactor).toAlignedRect()); + const auto dpr = m_frame.devicePixelRatio(); + repaint(QRectF(x / dpr * m_horizontalFactor, y / dpr * m_verticalFactor, w / dpr * m_horizontalFactor, h / dpr * m_verticalFactor).toAlignedRect()); } void VncView::setViewOnly(bool viewOnly) @@ -510,9 +515,10 @@ m_verticalFactor = 1.0; m_horizontalFactor = 1.0; - setMaximumSize(m_frame.width(), m_frame.height()); //This is a hack to force Qt to center the view in the scroll area - setMinimumSize(m_frame.width(), m_frame.height()); - resize(m_frame.width(), m_frame.height()); + const QSize frameSize = m_frame.size() / m_frame.devicePixelRatio(); + setMaximumSize(frameSize); //This is a hack to force Qt to center the view in the scroll area + setMinimumSize(frameSize); + resize(frameSize); } } @@ -537,9 +543,10 @@ QPainter painter(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); + const auto dpr = m_frame.devicePixelRatio(); QRectF dstRect = event->rect(); - QRectF srcRect(dstRect.x() / m_horizontalFactor, dstRect.y() / m_verticalFactor, - dstRect.width() / m_horizontalFactor, dstRect.height() / m_verticalFactor); + QRectF srcRect(dstRect.x() * dpr / m_horizontalFactor, dstRect.y() * dpr / m_verticalFactor, + dstRect.width() * dpr / m_horizontalFactor, dstRect.height() * dpr / m_verticalFactor); painter.drawImage(dstRect, m_frame, srcRect); RemoteView::paintEvent(event); @@ -599,7 +606,12 @@ } } - vncThread.mouseEvent(qRound(e->x() / m_horizontalFactor), qRound(e->y() / m_verticalFactor), m_buttonMask); + const auto dpr = devicePixelRatioF(); + QPointF screenPos = e->screenPos(); + // We need to restore mouse position in device coordinates. + // QMouseEvent::localPos() can be rounded (bug in Qt), but QMouseEvent::screenPos() is not. + QPointF pos = (e->pos() + (screenPos - screenPos.toPoint())) * dpr; + vncThread.mouseEvent(qRound(pos.x() / m_horizontalFactor), qRound(pos.y() / m_verticalFactor), m_buttonMask); } void VncView::wheelEventHandler(QWheelEvent *event)