blob: 98ef5862c1b975a66e88cc73605604a69241e621 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossmana4c0aac2017-02-19 15:50:29 +01002 * Copyright 2011-2017 Pierre Ossman for Cendio AB
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00003 *
4 * This is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This software is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17 * USA.
18 */
Pierre Ossmandd45b442018-10-31 17:08:59 +010019#include <assert.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000020#include <stdio.h>
21#include <string.h>
Pierre Ossman0068a4f2015-11-09 15:48:19 +010022
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rfb/Exception.h>
Pierre Ossmanc754cce2011-11-14 15:44:11 +000024#include <rfb/fenceTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010025#include <rfb/CMsgReader.h>
26#include <rfb/CMsgWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000027#include <rfb/CSecurity.h>
Pierre Ossman96728352018-06-20 11:35:05 +020028#include <rfb/Decoder.h>
Adam Tkac5a0caed2010-04-23 13:58:10 +000029#include <rfb/Security.h>
Pierre Ossman0068a4f2015-11-09 15:48:19 +010030#include <rfb/SecurityClient.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000031#include <rfb/CConnection.h>
32#include <rfb/util.h>
33
34#include <rfb/LogWriter.h>
35
Pierre Ossman0068a4f2015-11-09 15:48:19 +010036#include <rdr/InStream.h>
37#include <rdr/OutStream.h>
38
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000039using namespace rfb;
40
41static LogWriter vlog("CConnection");
42
43CConnection::CConnection()
Adam Tkacf324dc42010-04-23 14:10:17 +000044 : csecurity(0), is(0), os(0), reader_(0), writer_(0),
Adam Tkac05a0cd62010-07-20 15:07:44 +000045 shared(false),
Pierre Ossman9f273e92015-11-09 16:34:54 +010046 state_(RFBSTATE_UNINITIALISED), useProtocol3_3(false),
Pierre Ossmanef6881b2018-06-20 11:26:18 +020047 pendingPFChange(false), preferredEncoding(encodingTight),
48 formatChange(false), encodingChange(false),
49 firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
50 forceNonincremental(true),
Pierre Ossman9f273e92015-11-09 16:34:54 +010051 framebuffer(NULL), decoder(this)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000052{
53}
54
55CConnection::~CConnection()
56{
Pierre Ossman9f273e92015-11-09 16:34:54 +010057 setFramebuffer(NULL);
Pierre Ossman82d22e62018-09-21 15:26:37 +020058 if (csecurity)
59 delete csecurity;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000060 delete reader_;
61 reader_ = 0;
62 delete writer_;
63 writer_ = 0;
64}
65
66void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
67{
68 is = is_;
69 os = os_;
70}
71
Pierre Ossman9f273e92015-11-09 16:34:54 +010072void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
73{
Pierre Ossman504afa22015-11-12 12:21:58 +010074 decoder.flush();
75
Pierre Ossman6ea58ba2018-06-20 15:47:49 +020076 if (fb) {
77 assert(fb->width() == server.width());
78 assert(fb->height() == server.height());
79 }
80
Pierre Ossman9f273e92015-11-09 16:34:54 +010081 if ((framebuffer != NULL) && (fb != NULL)) {
82 Rect rect;
83
84 const rdr::U8* data;
85 int stride;
86
87 const rdr::U8 black[4] = { 0, 0, 0, 0 };
88
89 // Copy still valid area
90
91 rect.setXYWH(0, 0,
92 __rfbmin(fb->width(), framebuffer->width()),
93 __rfbmin(fb->height(), framebuffer->height()));
94 data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
95 fb->imageRect(rect, data, stride);
96
97 // Black out any new areas
98
99 if (fb->width() > framebuffer->width()) {
100 rect.setXYWH(framebuffer->width(), 0,
Brian P. Hinz5d663052016-09-05 09:15:50 -0400101 fb->width() - framebuffer->width(),
Pierre Ossman9f273e92015-11-09 16:34:54 +0100102 fb->height());
103 fb->fillRect(rect, black);
104 }
105
106 if (fb->height() > framebuffer->height()) {
107 rect.setXYWH(0, framebuffer->height(),
108 fb->width(),
109 fb->height() - framebuffer->height());
110 fb->fillRect(rect, black);
111 }
112 }
113
114 delete framebuffer;
115 framebuffer = fb;
116}
117
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000118void CConnection::initialiseProtocol()
119{
120 state_ = RFBSTATE_PROTOCOL_VERSION;
121}
122
123void CConnection::processMsg()
124{
125 switch (state_) {
126
127 case RFBSTATE_PROTOCOL_VERSION: processVersionMsg(); break;
128 case RFBSTATE_SECURITY_TYPES: processSecurityTypesMsg(); break;
129 case RFBSTATE_SECURITY: processSecurityMsg(); break;
130 case RFBSTATE_SECURITY_RESULT: processSecurityResultMsg(); break;
131 case RFBSTATE_INITIALISATION: processInitMsg(); break;
132 case RFBSTATE_NORMAL: reader_->readMsg(); break;
133 case RFBSTATE_UNINITIALISED:
134 throw Exception("CConnection::processMsg: not initialised yet?");
135 default:
136 throw Exception("CConnection::processMsg: invalid state");
137 }
138}
139
140void CConnection::processVersionMsg()
141{
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200142 char verStr[13];
143 int majorVersion;
144 int minorVersion;
145
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000146 vlog.debug("reading protocol version");
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200147
148 if (!is->checkNoWait(12))
149 return;
150
151 is->readBytes(verStr, 12);
152 verStr[12] = '\0';
153
154 if (sscanf(verStr, "RFB %03d.%03d\n",
155 &majorVersion, &minorVersion) != 2) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000156 state_ = RFBSTATE_INVALID;
157 throw Exception("reading version failed: not an RFB server?");
158 }
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200159
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200160 server.setVersion(majorVersion, minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000161
162 vlog.info("Server supports RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200163 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000164
165 // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200166 if (server.beforeVersion(3,3)) {
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100167 vlog.error("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200168 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169 state_ = RFBSTATE_INVALID;
Pierre Ossmana7bbe9c2015-03-03 16:17:51 +0100170 throw Exception("Server gave unsupported RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200171 server.majorVersion, server.minorVersion);
172 } else if (useProtocol3_3 || server.beforeVersion(3,7)) {
173 server.setVersion(3,3);
174 } else if (server.afterVersion(3,8)) {
175 server.setVersion(3,8);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000176 }
177
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200178 sprintf(verStr, "RFB %03d.%03d\n",
179 server.majorVersion, server.minorVersion);
Pierre Ossmanea7ede92018-06-18 16:51:53 +0200180 os->writeBytes(verStr, 12);
181 os->flush();
182
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000183 state_ = RFBSTATE_SECURITY_TYPES;
184
185 vlog.info("Using RFB protocol version %d.%d",
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200186 server.majorVersion, server.minorVersion);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000187}
188
189
190void CConnection::processSecurityTypesMsg()
191{
192 vlog.debug("processing security types message");
193
194 int secType = secTypeInvalid;
195
Adam Tkac05a0cd62010-07-20 15:07:44 +0000196 std::list<rdr::U8> secTypes;
Michal Srbdccb5f72017-03-27 13:55:46 +0300197 secTypes = security.GetEnabledSecTypes();
Adam Tkac05a0cd62010-07-20 15:07:44 +0000198
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200199 if (server.isVersion(3,3)) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000200
201 // legacy 3.3 server may only offer "vnc authentication" or "none"
202
203 secType = is->readU32();
204 if (secType == secTypeInvalid) {
205 throwConnFailedException();
206
207 } else if (secType == secTypeNone || secType == secTypeVncAuth) {
Adam Tkac05a0cd62010-07-20 15:07:44 +0000208 std::list<rdr::U8>::iterator i;
209 for (i = secTypes.begin(); i != secTypes.end(); i++)
210 if (*i == secType) {
211 secType = *i;
212 break;
213 }
214
215 if (i == secTypes.end())
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000216 secType = secTypeInvalid;
217 } else {
218 vlog.error("Unknown 3.3 security type %d", secType);
219 throw Exception("Unknown 3.3 security type");
220 }
221
222 } else {
223
224 // >=3.7 server will offer us a list
225
226 int nServerSecTypes = is->readU8();
227 if (nServerSecTypes == 0)
228 throwConnFailedException();
229
Adam Tkac05a0cd62010-07-20 15:07:44 +0000230 std::list<rdr::U8>::iterator j;
Adam Tkac05a0cd62010-07-20 15:07:44 +0000231
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000232 for (int i = 0; i < nServerSecTypes; i++) {
233 rdr::U8 serverSecType = is->readU8();
234 vlog.debug("Server offers security type %s(%d)",
Adam Tkac7cb47d62011-02-21 12:55:24 +0000235 secTypeName(serverSecType), serverSecType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000236
Adam Tkac7cb47d62011-02-21 12:55:24 +0000237 /*
238 * Use the first type sent by server which matches client's type.
239 * It means server's order specifies priority.
240 */
241 if (secType == secTypeInvalid) {
242 for (j = secTypes.begin(); j != secTypes.end(); j++)
243 if (*j == serverSecType) {
244 secType = *j;
245 break;
246 }
247 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000248 }
249
250 // Inform the server of our decision
251 if (secType != secTypeInvalid) {
252 os->writeU8(secType);
253 os->flush();
Pierre Ossman71d66662014-11-11 13:42:51 +0100254 vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000255 }
256 }
257
258 if (secType == secTypeInvalid) {
259 state_ = RFBSTATE_INVALID;
260 vlog.error("No matching security types");
261 throw Exception("No matching security types");
262 }
263
264 state_ = RFBSTATE_SECURITY;
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200265 csecurity = security.GetCSecurity(this, secType);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000266 processSecurityMsg();
267}
268
269void CConnection::processSecurityMsg()
270{
271 vlog.debug("processing security message");
Pierre Ossmanad2b3c42018-09-21 15:31:11 +0200272 if (csecurity->processMsg()) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000273 state_ = RFBSTATE_SECURITY_RESULT;
274 processSecurityResultMsg();
275 }
276}
277
278void CConnection::processSecurityResultMsg()
279{
280 vlog.debug("processing security result message");
281 int result;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200282 if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000283 result = secResultOK;
284 } else {
285 if (!is->checkNoWait(1)) return;
286 result = is->readU32();
287 }
288 switch (result) {
289 case secResultOK:
290 securityCompleted();
291 return;
292 case secResultFailed:
293 vlog.debug("auth failed");
294 break;
295 case secResultTooMany:
296 vlog.debug("auth failed - too many tries");
297 break;
298 default:
299 throw Exception("Unknown security result from server");
300 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000301 state_ = RFBSTATE_INVALID;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200302 if (server.beforeVersion(3,8))
Pierre Ossman19225502017-10-12 15:05:07 +0200303 throw AuthFailureException();
304 CharArray reason(is->readString());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000305 throw AuthFailureException(reason.buf);
306}
307
308void CConnection::processInitMsg()
309{
310 vlog.debug("reading server initialisation");
311 reader_->readServerInit();
312}
313
314void CConnection::throwConnFailedException()
315{
316 state_ = RFBSTATE_INVALID;
317 CharArray reason;
318 reason.buf = is->readString();
319 throw ConnFailedException(reason.buf);
320}
321
322void CConnection::securityCompleted()
323{
324 state_ = RFBSTATE_INITIALISATION;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100325 reader_ = new CMsgReader(this, is);
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200326 writer_ = new CMsgWriter(&server, os);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000327 vlog.debug("Authentication success!");
328 authSuccess();
329 writer_->writeClientInit(shared);
330}
331
Pierre Ossman3da238d2015-11-12 12:20:05 +0100332void CConnection::setDesktopSize(int w, int h)
333{
Pierre Ossman504afa22015-11-12 12:21:58 +0100334 decoder.flush();
335
Pierre Ossman3da238d2015-11-12 12:20:05 +0100336 CMsgHandler::setDesktopSize(w,h);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200337
338 if (continuousUpdates)
339 writer()->writeEnableContinuousUpdates(true, 0, 0,
340 server.width(),
341 server.height());
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200342
343 resizeFramebuffer();
344 assert(framebuffer != NULL);
345 assert(framebuffer->width() == server.width());
346 assert(framebuffer->height() == server.height());
Pierre Ossman3da238d2015-11-12 12:20:05 +0100347}
348
349void CConnection::setExtendedDesktopSize(unsigned reason,
350 unsigned result,
351 int w, int h,
352 const ScreenSet& layout)
353{
Pierre Ossman504afa22015-11-12 12:21:58 +0100354 decoder.flush();
355
Pierre Ossman3da238d2015-11-12 12:20:05 +0100356 CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200357
358 if (continuousUpdates)
359 writer()->writeEnableContinuousUpdates(true, 0, 0,
360 server.width(),
361 server.height());
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200362
363 resizeFramebuffer();
364 assert(framebuffer != NULL);
365 assert(framebuffer->width() == server.width());
366 assert(framebuffer->height() == server.height());
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200367}
368
369void CConnection::endOfContinuousUpdates()
370{
371 CMsgHandler::endOfContinuousUpdates();
372
373 // We've gotten the marker for a format change, so make the pending
374 // one active
375 if (pendingPFChange) {
376 server.setPF(pendingPF);
377 pendingPFChange = false;
378
379 // We might have another change pending
380 if (formatChange)
381 requestNewUpdate();
382 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100383}
384
Pierre Ossmandd45b442018-10-31 17:08:59 +0100385void CConnection::serverInit(int width, int height,
386 const PixelFormat& pf,
387 const char* name)
Pierre Ossman2affd772018-06-20 07:03:10 +0200388{
Pierre Ossmandd45b442018-10-31 17:08:59 +0100389 CMsgHandler::serverInit(width, height, pf, name);
390
Pierre Ossman2affd772018-06-20 07:03:10 +0200391 state_ = RFBSTATE_NORMAL;
392 vlog.debug("initialisation done");
393
394 initDone();
Pierre Ossmandd45b442018-10-31 17:08:59 +0100395 assert(framebuffer != NULL);
396 assert(framebuffer->width() == server.width());
397 assert(framebuffer->height() == server.height());
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200398
399 // We want to make sure we call SetEncodings at least once
400 encodingChange = true;
401
402 requestNewUpdate();
403
404 // This initial update request is a bit of a corner case, so we need
405 // to help out setting the correct format here.
406 if (pendingPFChange) {
407 server.setPF(pendingPF);
408 pendingPFChange = false;
409 }
Pierre Ossman2affd772018-06-20 07:03:10 +0200410}
411
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100412void CConnection::readAndDecodeRect(const Rect& r, int encoding,
413 ModifiablePixelBuffer* pb)
414{
415 decoder.decodeRect(r, encoding, pb);
416 decoder.flush();
417}
418
Pierre Ossman3da238d2015-11-12 12:20:05 +0100419void CConnection::framebufferUpdateStart()
420{
421 CMsgHandler::framebufferUpdateStart();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200422
423 assert(framebuffer != NULL);
424
425 // Note: This might not be true if continuous updates are supported
426 pendingUpdate = false;
427
428 requestNewUpdate();
Pierre Ossman3da238d2015-11-12 12:20:05 +0100429}
430
431void CConnection::framebufferUpdateEnd()
432{
Pierre Ossman504afa22015-11-12 12:21:58 +0100433 decoder.flush();
434
Pierre Ossman3da238d2015-11-12 12:20:05 +0100435 CMsgHandler::framebufferUpdateEnd();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200436
437 // A format change has been scheduled and we are now past the update
438 // with the old format. Time to active the new one.
439 if (pendingPFChange && !continuousUpdates) {
440 server.setPF(pendingPF);
441 pendingPFChange = false;
442 }
443
444 if (firstUpdate) {
445 if (server.supportsContinuousUpdates) {
446 vlog.info("Enabling continuous updates");
447 continuousUpdates = true;
448 writer()->writeEnableContinuousUpdates(true, 0, 0,
449 server.width(),
450 server.height());
451 }
452
453 firstUpdate = false;
454 }
Pierre Ossman3da238d2015-11-12 12:20:05 +0100455}
456
Pierre Ossman9f273e92015-11-09 16:34:54 +0100457void CConnection::dataRect(const Rect& r, int encoding)
458{
459 decoder.decodeRect(r, encoding, framebuffer);
460}
461
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000462void CConnection::authSuccess()
463{
464}
465
Pierre Ossman2affd772018-06-20 07:03:10 +0200466void CConnection::initDone()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000467{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000468}
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000469
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200470void CConnection::resizeFramebuffer()
471{
472 assert(false);
473}
474
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200475void CConnection::refreshFramebuffer()
476{
477 forceNonincremental = true;
478
479 // Without continuous updates we have to make sure we only have a
480 // single update in flight, so we'll have to wait to do the refresh
481 if (continuousUpdates)
482 requestNewUpdate();
483}
484
485void CConnection::setPreferredEncoding(int encoding)
486{
487 if (preferredEncoding == encoding)
488 return;
489
490 preferredEncoding = encoding;
491 encodingChange = true;
492}
493
494int CConnection::getPreferredEncoding()
495{
496 return preferredEncoding;
497}
498
499void CConnection::setCompressLevel(int level)
500{
501 if (server.compressLevel == level)
502 return;
503
504 server.compressLevel = level;
505 encodingChange = true;
506}
507
508void CConnection::setQualityLevel(int level)
509{
510 if (server.qualityLevel == level)
511 return;
512
513 server.qualityLevel = level;
514 encodingChange = true;
515}
516
517void CConnection::setPF(const PixelFormat& pf)
518{
519 if (server.pf().equal(pf) && !formatChange)
520 return;
521
522 nextPF = pf;
523 formatChange = true;
524}
525
Pierre Ossmanc754cce2011-11-14 15:44:11 +0000526void CConnection::fence(rdr::U32 flags, unsigned len, const char data[])
527{
528 CMsgHandler::fence(flags, len, data);
529
530 if (!(flags & fenceFlagRequest))
531 return;
532
533 // We cannot guarantee any synchronisation at this level
534 flags = 0;
535
536 writer()->writeFence(flags, len, data);
537}
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200538
539// requestNewUpdate() requests an update from the server, having set the
540// format and encoding appropriately.
541void CConnection::requestNewUpdate()
542{
543 if (formatChange && !pendingPFChange) {
544 /* Catch incorrect requestNewUpdate calls */
545 assert(!pendingUpdate || continuousUpdates);
546
547 // We have to make sure we switch the internal format at a safe
548 // time. For continuous updates we temporarily disable updates and
549 // look for a EndOfContinuousUpdates message to see when to switch.
550 // For classical updates we just got a new update right before this
551 // function was called, so we need to make sure we finish that
552 // update before we can switch.
553
554 pendingPFChange = true;
555 pendingPF = nextPF;
556
557 if (continuousUpdates)
558 writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
559
560 writer()->writeSetPixelFormat(pendingPF);
561
562 if (continuousUpdates)
563 writer()->writeEnableContinuousUpdates(true, 0, 0,
564 server.width(),
565 server.height());
566
567 formatChange = false;
568 }
569
570 if (encodingChange) {
Pierre Ossman96728352018-06-20 11:35:05 +0200571 updateEncodings();
Pierre Ossmanef6881b2018-06-20 11:26:18 +0200572 encodingChange = false;
573 }
574
575 if (forceNonincremental || !continuousUpdates) {
576 pendingUpdate = true;
577 writer()->writeFramebufferUpdateRequest(Rect(0, 0,
578 server.width(),
579 server.height()),
580 !forceNonincremental);
581 }
582
583 forceNonincremental = false;
584}
Pierre Ossman96728352018-06-20 11:35:05 +0200585
586// Ask for encodings based on which decoders are supported. Assumes higher
587// encoding numbers are more desirable.
588
589void CConnection::updateEncodings()
590{
Pierre Ossman1143ee62018-06-20 11:40:37 +0200591 std::list<rdr::U32> encodings;
Pierre Ossman96728352018-06-20 11:35:05 +0200592
593 if (server.supportsLocalCursor) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200594 encodings.push_back(pseudoEncodingCursorWithAlpha);
595 encodings.push_back(pseudoEncodingCursor);
596 encodings.push_back(pseudoEncodingXCursor);
Pierre Ossman96728352018-06-20 11:35:05 +0200597 }
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200598 if (server.supportsDesktopResize) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200599 encodings.push_back(pseudoEncodingDesktopSize);
Pierre Ossman1143ee62018-06-20 11:40:37 +0200600 encodings.push_back(pseudoEncodingExtendedDesktopSize);
Pierre Ossman6ea58ba2018-06-20 15:47:49 +0200601 }
Pierre Ossman96728352018-06-20 11:35:05 +0200602 if (server.supportsLEDState)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200603 encodings.push_back(pseudoEncodingLEDState);
Pierre Ossman96728352018-06-20 11:35:05 +0200604
Pierre Ossman5588f4f2018-06-20 11:48:17 +0200605 encodings.push_back(pseudoEncodingDesktopName);
Pierre Ossman1143ee62018-06-20 11:40:37 +0200606 encodings.push_back(pseudoEncodingLastRect);
607 encodings.push_back(pseudoEncodingContinuousUpdates);
608 encodings.push_back(pseudoEncodingFence);
609 encodings.push_back(pseudoEncodingQEMUKeyEvent);
Pierre Ossman96728352018-06-20 11:35:05 +0200610
611 if (Decoder::supported(preferredEncoding)) {
Pierre Ossman1143ee62018-06-20 11:40:37 +0200612 encodings.push_back(preferredEncoding);
Pierre Ossman96728352018-06-20 11:35:05 +0200613 }
614
Pierre Ossman1143ee62018-06-20 11:40:37 +0200615 encodings.push_back(encodingCopyRect);
Pierre Ossman96728352018-06-20 11:35:05 +0200616
Pierre Ossman96728352018-06-20 11:35:05 +0200617 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman3bbe8d72018-06-20 11:42:36 +0200618 if ((i != preferredEncoding) && Decoder::supported(i))
619 encodings.push_back(i);
Pierre Ossman96728352018-06-20 11:35:05 +0200620 }
621
622 if (server.compressLevel >= 0 && server.compressLevel <= 9)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200623 encodings.push_back(pseudoEncodingCompressLevel0 + server.compressLevel);
Pierre Ossman96728352018-06-20 11:35:05 +0200624 if (server.qualityLevel >= 0 && server.qualityLevel <= 9)
Pierre Ossman1143ee62018-06-20 11:40:37 +0200625 encodings.push_back(pseudoEncodingQualityLevel0 + server.qualityLevel);
Pierre Ossman96728352018-06-20 11:35:05 +0200626
Pierre Ossman1143ee62018-06-20 11:40:37 +0200627 writer()->writeSetEncodings(encodings);
Pierre Ossman96728352018-06-20 11:35:05 +0200628}