Commit c818ea57 authored by Eskil Abrahamsen-Blomfeldt's avatar Eskil Abrahamsen-Blomfeldt
Browse files

Make it possible to choose encoding preference for server

The server encoding preference can now be customized with
QT_VNCSERVER_PREFERRED_ENCODING environment variable. Set this
to a semi-colon-separated list of encodings. The first that is
supported by the client will be picked. If none are supported
by the client, the client's first supported preference will be
chosen instead.

E.g.: QT_VNCSERVER_PREFERRED_ENCODING=hextile;zlib

This would make the server prefer hextile over zlib, even if the
client prefers zlib.
parent 1979bf0f
......@@ -239,14 +239,7 @@ int QVncClient::sharedButtonState = Qt::NoButton;
QVncClient::QVncClient(QVncServer *server)
: QObject(nullptr)
, m_server(server)
, m_supportCopyRect(false)
, m_supportRRE(false)
, m_supportCoRRE(false)
, m_supportHextile(false)
, m_supportZRLE(false)
, m_supportCursor(false)
, m_supportDesktopSize(false)
, m_supportZlib(false)
{
}
......@@ -933,6 +926,49 @@ static const char *encodingName(qint32 enc)
}
}
static QList<QVncClient::Encodings> queryServerEncodings()
{
static const char *serverEncodingEnvironmentVariable = "QT_VNCSERVER_PREFERRED_ENCODING";
QStringList names =
qEnvironmentVariable(serverEncodingEnvironmentVariable).split(QLatin1Char(';'));
QHash<QString, QVncClient::Encodings> map;
for (int encoding : { QVncClient::Raw, QVncClient::Hextile, QVncClient::Zlib})
map[QString::fromUtf8(encodingName(encoding)).toLower()] = QVncClient::Encodings(encoding);
QList<QVncClient::Encodings> ret;
for (const QString &name : names) {
QVncClient::Encodings value = map.value(name.toLower(), QVncClient::Encodings(-1));
if (value != QVncClient::Encodings(-1))
ret.append(value);
}
return ret;
}
QRfbEncoder *QVncClient::createEncoder(QVncClient::Encodings encoding)
{
QRfbEncoder *ret = nullptr;
switch (encoding) {
case Raw:
ret = new QRfbRawEncoder(this);
break;
case Hextile:
ret = new QRfbHextileEncoder<quint32>(this); //TODO: more formats
break;
case Zlib:
ret = new QRfbRawEncoder(this);
if (m_zlibStream == nullptr) {
m_zlibStream = new z_stream_s;
memset(m_zlibStream, 0, sizeof(z_stream_s));
::deflateInit2(m_zlibStream, -1, Z_DEFLATED, MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
}
default:
break;
};
return ret;
}
void QVncClient::setEncodings()
{
......@@ -944,14 +980,16 @@ void QVncClient::setEncodings()
m_handleMsg = false;
}
if (m_encoder) {
if (m_encoder != nullptr) {
delete m_encoder;
m_encoder = nullptr;
}
if (m_encodingsPending && (unsigned)m_clientSocket->bytesAvailable() >=
m_encodingsPending * sizeof(quint32)) {
static bool skipZlib = qEnvironmentVariableIntValue("QT_VNC_NO_ZLIB");
static QList<Encodings> serverEncodingPreferences = queryServerEncodings();
QList<Encodings> clientEncodingPreferences;
for (int i = 0; i < m_encodingsPending; ++i) {
qint32 enc;
m_clientSocket->read((char *)&enc, sizeof(qint32));
......@@ -960,50 +998,17 @@ void QVncClient::setEncodings()
switch (enc) {
case Raw:
if (!m_encoder) {
m_encoder = new QRfbRawEncoder(this);
m_supportZlib = false;
qCDebug(lcVnc, "QVncClient::setEncodings: using raw");
}
clientEncodingPreferences.append(Raw);
break;
case CopyRect:
m_supportCopyRect = true;
break;
case RRE:
m_supportRRE = true;
break;
case CoRRE:
m_supportCoRRE = true;
break;
case Hextile:
m_supportHextile = true;
if (!m_encoder) {
qCDebug(lcVnc) << "QVncClient::setEncodings: using Hextile";
m_encoder = new QRfbHextileEncoder<quint32>(this); //TODO: more formats
}
clientEncodingPreferences.append(Hextile);
break;
case Zlib:
#if !defined(QT_VNCSERVER_NO_ZLIB)
if (!skipZlib && m_encoder == nullptr) {
m_encoder = new QRfbRawEncoder(this);
m_supportZlib = true;
if (m_zlibStream == nullptr) {
qCDebug(lcVnc, "QVncClient::setEncodings: Initializing new zlib stream");
m_zlibStream = new z_stream_s;
memset(m_zlibStream, 0, sizeof(z_stream_s));
::deflateInit2(m_zlibStream, -1, Z_DEFLATED, MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
}
qCDebug(lcVnc, "QVncClient::setEncodings: using zlib");
}
clientEncodingPreferences.append(Zlib);
#endif
break;
case ZRLE:
m_supportZRLE = true;
break;
case Cursor:
m_supportCursor = true;
m_server->enableClientCursor(this);
break;
case DesktopSize:
......@@ -1013,14 +1018,34 @@ void QVncClient::setEncodings()
break;
}
}
for (QVncClient::Encodings serverPreference : serverEncodingPreferences) {
if (clientEncodingPreferences.contains(serverPreference)) {
qCDebug(lcVnc) << "QVncClient::setEncodings: using server preferred encoding"
<< QString::fromLatin1(encodingName(serverPreference));
m_encoder = createEncoder(serverPreference);
m_currentEncoding = serverPreference;
break;
}
}
if (m_encoder == nullptr) {
for (QVncClient::Encodings clientPreference : clientEncodingPreferences) {
qCDebug(lcVnc) << "QVncClient::setEncodings: using client preferred encoding"
<< QString::fromLatin1(encodingName(clientPreference));
m_encoder = createEncoder(clientPreference);
m_currentEncoding = clientPreference;
break;
}
}
m_handleMsg = false;
m_encodingsPending = 0;
}
if (!m_encoder) {
if (m_encoder == nullptr) {
m_encoder = new QRfbRawEncoder(this);
m_supportZlib = false;
m_currentEncoding = Raw;
qCDebug(lcVnc, "QVncClient::setEncodings: fallback using raw");
}
}
......
......@@ -113,10 +113,9 @@ public:
bool dirtyMapTestAndClean(int x, int y);
int dirtyMapCount() const;
z_stream_s *zlibStream() const
{
return m_supportZlib ? m_zlibStream : nullptr;
return m_currentEncoding == Zlib ? m_zlibStream : nullptr;
}
QImage currentImage() { return m_currentImage; }
......@@ -155,6 +154,7 @@ protected:
bool event(QEvent *event) override;
private:
QRfbEncoder *createEncoder(Encodings encoding);
QRegion dirtyRegion() const { return m_dirtyRegion; }
enum ClientState {
......@@ -190,6 +190,7 @@ private:
qintptr m_socketHandle = 0;
qsizetype m_bytesWritten = 0;
QElapsedTimer m_frameTimer;
QVncClient::Encodings m_currentEncoding = QVncClient::Raw;
// Client State
quint8 m_msgType = 0;
......@@ -201,14 +202,7 @@ private:
int m_encodingsPending = false;
int m_cutTextPending = false;
uint m_supportCopyRect : 1;
uint m_supportRRE : 1;
uint m_supportCoRRE : 1;
uint m_supportHextile : 1;
uint m_supportZRLE : 1;
uint m_supportCursor : 1;
uint m_supportDesktopSize : 1;
uint m_supportZlib : 1;
Qt::KeyboardModifiers m_keymod;
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment