You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CConnection.cxx 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2011-2019 Pierre Ossman for Cendio AB
  3. *
  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. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <assert.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <rfb/Exception.h>
  26. #include <rfb/clipboardTypes.h>
  27. #include <rfb/fenceTypes.h>
  28. #include <rfb/CMsgReader.h>
  29. #include <rfb/CMsgWriter.h>
  30. #include <rfb/CSecurity.h>
  31. #include <rfb/Decoder.h>
  32. #include <rfb/Security.h>
  33. #include <rfb/SecurityClient.h>
  34. #include <rfb/CConnection.h>
  35. #include <rfb/util.h>
  36. #include <rfb/LogWriter.h>
  37. #include <rdr/InStream.h>
  38. #include <rdr/OutStream.h>
  39. using namespace rfb;
  40. static LogWriter vlog("CConnection");
  41. CConnection::CConnection()
  42. : csecurity(0),
  43. supportsLocalCursor(false), supportsCursorPosition(false),
  44. supportsDesktopResize(false), supportsLEDState(false),
  45. is(0), os(0), reader_(0), writer_(0),
  46. shared(false),
  47. state_(RFBSTATE_UNINITIALISED), serverName(strDup("")),
  48. pendingPFChange(false), preferredEncoding(encodingTight),
  49. compressLevel(2), qualityLevel(-1),
  50. formatChange(false), encodingChange(false),
  51. firstUpdate(true), pendingUpdate(false), continuousUpdates(false),
  52. forceNonincremental(true),
  53. framebuffer(NULL), decoder(this),
  54. serverClipboard(NULL), hasLocalClipboard(false)
  55. {
  56. }
  57. CConnection::~CConnection()
  58. {
  59. close();
  60. }
  61. void CConnection::setServerName(const char* name_)
  62. {
  63. if (name_ == NULL)
  64. name_ = "";
  65. serverName.replaceBuf(strDup(name_));
  66. }
  67. void CConnection::setStreams(rdr::InStream* is_, rdr::OutStream* os_)
  68. {
  69. is = is_;
  70. os = os_;
  71. }
  72. void CConnection::setFramebuffer(ModifiablePixelBuffer* fb)
  73. {
  74. decoder.flush();
  75. if (fb) {
  76. assert(fb->width() == server.width());
  77. assert(fb->height() == server.height());
  78. }
  79. if ((framebuffer != NULL) && (fb != NULL)) {
  80. Rect rect;
  81. const uint8_t* data;
  82. int stride;
  83. const uint8_t black[4] = { 0, 0, 0, 0 };
  84. // Copy still valid area
  85. rect.setXYWH(0, 0,
  86. __rfbmin(fb->width(), framebuffer->width()),
  87. __rfbmin(fb->height(), framebuffer->height()));
  88. data = framebuffer->getBuffer(framebuffer->getRect(), &stride);
  89. fb->imageRect(rect, data, stride);
  90. // Black out any new areas
  91. if (fb->width() > framebuffer->width()) {
  92. rect.setXYWH(framebuffer->width(), 0,
  93. fb->width() - framebuffer->width(),
  94. fb->height());
  95. fb->fillRect(rect, black);
  96. }
  97. if (fb->height() > framebuffer->height()) {
  98. rect.setXYWH(0, framebuffer->height(),
  99. fb->width(),
  100. fb->height() - framebuffer->height());
  101. fb->fillRect(rect, black);
  102. }
  103. }
  104. delete framebuffer;
  105. framebuffer = fb;
  106. }
  107. void CConnection::initialiseProtocol()
  108. {
  109. state_ = RFBSTATE_PROTOCOL_VERSION;
  110. }
  111. bool CConnection::processMsg()
  112. {
  113. switch (state_) {
  114. case RFBSTATE_PROTOCOL_VERSION: return processVersionMsg(); break;
  115. case RFBSTATE_SECURITY_TYPES: return processSecurityTypesMsg(); break;
  116. case RFBSTATE_SECURITY: return processSecurityMsg(); break;
  117. case RFBSTATE_SECURITY_RESULT: return processSecurityResultMsg(); break;
  118. case RFBSTATE_SECURITY_REASON: return processSecurityReasonMsg(); break;
  119. case RFBSTATE_INITIALISATION: return processInitMsg(); break;
  120. case RFBSTATE_NORMAL: return reader_->readMsg(); break;
  121. case RFBSTATE_CLOSING:
  122. throw Exception("CConnection::processMsg: called while closing");
  123. case RFBSTATE_UNINITIALISED:
  124. throw Exception("CConnection::processMsg: not initialised yet?");
  125. default:
  126. throw Exception("CConnection::processMsg: invalid state");
  127. }
  128. }
  129. bool CConnection::processVersionMsg()
  130. {
  131. char verStr[27]; // FIXME: gcc has some bug in format-overflow
  132. int majorVersion;
  133. int minorVersion;
  134. vlog.debug("reading protocol version");
  135. if (!is->hasData(12))
  136. return false;
  137. is->readBytes(verStr, 12);
  138. verStr[12] = '\0';
  139. if (sscanf(verStr, "RFB %03d.%03d\n",
  140. &majorVersion, &minorVersion) != 2) {
  141. state_ = RFBSTATE_INVALID;
  142. throw Exception("reading version failed: not an RFB server?");
  143. }
  144. server.setVersion(majorVersion, minorVersion);
  145. vlog.info("Server supports RFB protocol version %d.%d",
  146. server.majorVersion, server.minorVersion);
  147. // The only official RFB protocol versions are currently 3.3, 3.7 and 3.8
  148. if (server.beforeVersion(3,3)) {
  149. vlog.error("Server gave unsupported RFB protocol version %d.%d",
  150. server.majorVersion, server.minorVersion);
  151. state_ = RFBSTATE_INVALID;
  152. throw Exception("Server gave unsupported RFB protocol version %d.%d",
  153. server.majorVersion, server.minorVersion);
  154. } else if (server.beforeVersion(3,7)) {
  155. server.setVersion(3,3);
  156. } else if (server.afterVersion(3,8)) {
  157. server.setVersion(3,8);
  158. }
  159. sprintf(verStr, "RFB %03d.%03d\n",
  160. server.majorVersion, server.minorVersion);
  161. os->writeBytes(verStr, 12);
  162. os->flush();
  163. state_ = RFBSTATE_SECURITY_TYPES;
  164. vlog.info("Using RFB protocol version %d.%d",
  165. server.majorVersion, server.minorVersion);
  166. return true;
  167. }
  168. bool CConnection::processSecurityTypesMsg()
  169. {
  170. vlog.debug("processing security types message");
  171. int secType = secTypeInvalid;
  172. std::list<uint8_t> secTypes;
  173. secTypes = security.GetEnabledSecTypes();
  174. if (server.isVersion(3,3)) {
  175. // legacy 3.3 server may only offer "vnc authentication" or "none"
  176. if (!is->hasData(4))
  177. return false;
  178. secType = is->readU32();
  179. if (secType == secTypeInvalid) {
  180. state_ = RFBSTATE_SECURITY_REASON;
  181. return true;
  182. } else if (secType == secTypeNone || secType == secTypeVncAuth) {
  183. std::list<uint8_t>::iterator i;
  184. for (i = secTypes.begin(); i != secTypes.end(); i++)
  185. if (*i == secType) {
  186. secType = *i;
  187. break;
  188. }
  189. if (i == secTypes.end())
  190. secType = secTypeInvalid;
  191. } else {
  192. vlog.error("Unknown 3.3 security type %d", secType);
  193. throw Exception("Unknown 3.3 security type");
  194. }
  195. } else {
  196. // >=3.7 server will offer us a list
  197. if (!is->hasData(1))
  198. return false;
  199. is->setRestorePoint();
  200. int nServerSecTypes = is->readU8();
  201. if (!is->hasDataOrRestore(nServerSecTypes))
  202. return false;
  203. is->clearRestorePoint();
  204. if (nServerSecTypes == 0) {
  205. state_ = RFBSTATE_SECURITY_REASON;
  206. return true;
  207. }
  208. std::list<uint8_t>::iterator j;
  209. for (int i = 0; i < nServerSecTypes; i++) {
  210. uint8_t serverSecType = is->readU8();
  211. vlog.debug("Server offers security type %s(%d)",
  212. secTypeName(serverSecType), serverSecType);
  213. /*
  214. * Use the first type sent by server which matches client's type.
  215. * It means server's order specifies priority.
  216. */
  217. if (secType == secTypeInvalid) {
  218. for (j = secTypes.begin(); j != secTypes.end(); j++)
  219. if (*j == serverSecType) {
  220. secType = *j;
  221. break;
  222. }
  223. }
  224. }
  225. // Inform the server of our decision
  226. if (secType != secTypeInvalid) {
  227. os->writeU8(secType);
  228. os->flush();
  229. vlog.info("Choosing security type %s(%d)",secTypeName(secType),secType);
  230. }
  231. }
  232. if (secType == secTypeInvalid) {
  233. state_ = RFBSTATE_INVALID;
  234. vlog.error("No matching security types");
  235. throw Exception("No matching security types");
  236. }
  237. state_ = RFBSTATE_SECURITY;
  238. csecurity = security.GetCSecurity(this, secType);
  239. return true;
  240. }
  241. bool CConnection::processSecurityMsg()
  242. {
  243. vlog.debug("processing security message");
  244. if (!csecurity->processMsg())
  245. return false;
  246. state_ = RFBSTATE_SECURITY_RESULT;
  247. return true;
  248. }
  249. bool CConnection::processSecurityResultMsg()
  250. {
  251. vlog.debug("processing security result message");
  252. int result;
  253. if (server.beforeVersion(3,8) && csecurity->getType() == secTypeNone) {
  254. result = secResultOK;
  255. } else {
  256. if (!is->hasData(4))
  257. return false;
  258. result = is->readU32();
  259. }
  260. switch (result) {
  261. case secResultOK:
  262. securityCompleted();
  263. return true;
  264. case secResultFailed:
  265. vlog.debug("auth failed");
  266. break;
  267. case secResultTooMany:
  268. vlog.debug("auth failed - too many tries");
  269. break;
  270. default:
  271. throw Exception("Unknown security result from server");
  272. }
  273. if (server.beforeVersion(3,8)) {
  274. state_ = RFBSTATE_INVALID;
  275. throw AuthFailureException();
  276. }
  277. state_ = RFBSTATE_SECURITY_REASON;
  278. return true;
  279. }
  280. bool CConnection::processSecurityReasonMsg()
  281. {
  282. vlog.debug("processing security reason message");
  283. if (!is->hasData(4))
  284. return false;
  285. is->setRestorePoint();
  286. uint32_t len = is->readU32();
  287. if (!is->hasDataOrRestore(len))
  288. return false;
  289. is->clearRestorePoint();
  290. CharArray reason(len + 1);
  291. is->readBytes(reason.buf, len);
  292. reason.buf[len] = '\0';
  293. state_ = RFBSTATE_INVALID;
  294. throw AuthFailureException(reason.buf);
  295. }
  296. bool CConnection::processInitMsg()
  297. {
  298. vlog.debug("reading server initialisation");
  299. return reader_->readServerInit();
  300. }
  301. void CConnection::securityCompleted()
  302. {
  303. state_ = RFBSTATE_INITIALISATION;
  304. reader_ = new CMsgReader(this, is);
  305. writer_ = new CMsgWriter(&server, os);
  306. vlog.debug("Authentication success!");
  307. authSuccess();
  308. writer_->writeClientInit(shared);
  309. }
  310. void CConnection::close()
  311. {
  312. state_ = RFBSTATE_CLOSING;
  313. /*
  314. * We're already shutting down, so just log any pending decoder
  315. * problems
  316. */
  317. try {
  318. decoder.flush();
  319. } catch (rdr::Exception& e) {
  320. vlog.error("%s", e.str());
  321. }
  322. setFramebuffer(NULL);
  323. delete csecurity;
  324. csecurity = NULL;
  325. delete reader_;
  326. reader_ = NULL;
  327. delete writer_;
  328. writer_ = NULL;
  329. strFree(serverClipboard);
  330. serverClipboard = NULL;
  331. }
  332. void CConnection::setDesktopSize(int w, int h)
  333. {
  334. decoder.flush();
  335. CMsgHandler::setDesktopSize(w,h);
  336. if (continuousUpdates)
  337. writer()->writeEnableContinuousUpdates(true, 0, 0,
  338. server.width(),
  339. server.height());
  340. resizeFramebuffer();
  341. assert(framebuffer != NULL);
  342. assert(framebuffer->width() == server.width());
  343. assert(framebuffer->height() == server.height());
  344. }
  345. void CConnection::setExtendedDesktopSize(unsigned reason,
  346. unsigned result,
  347. int w, int h,
  348. const ScreenSet& layout)
  349. {
  350. decoder.flush();
  351. CMsgHandler::setExtendedDesktopSize(reason, result, w, h, layout);
  352. if (continuousUpdates)
  353. writer()->writeEnableContinuousUpdates(true, 0, 0,
  354. server.width(),
  355. server.height());
  356. resizeFramebuffer();
  357. assert(framebuffer != NULL);
  358. assert(framebuffer->width() == server.width());
  359. assert(framebuffer->height() == server.height());
  360. }
  361. void CConnection::endOfContinuousUpdates()
  362. {
  363. CMsgHandler::endOfContinuousUpdates();
  364. // We've gotten the marker for a format change, so make the pending
  365. // one active
  366. if (pendingPFChange) {
  367. server.setPF(pendingPF);
  368. pendingPFChange = false;
  369. // We might have another change pending
  370. if (formatChange)
  371. requestNewUpdate();
  372. }
  373. }
  374. void CConnection::serverInit(int width, int height,
  375. const PixelFormat& pf,
  376. const char* name)
  377. {
  378. CMsgHandler::serverInit(width, height, pf, name);
  379. state_ = RFBSTATE_NORMAL;
  380. vlog.debug("initialisation done");
  381. initDone();
  382. assert(framebuffer != NULL);
  383. assert(framebuffer->width() == server.width());
  384. assert(framebuffer->height() == server.height());
  385. // We want to make sure we call SetEncodings at least once
  386. encodingChange = true;
  387. requestNewUpdate();
  388. // This initial update request is a bit of a corner case, so we need
  389. // to help out setting the correct format here.
  390. if (pendingPFChange) {
  391. server.setPF(pendingPF);
  392. pendingPFChange = false;
  393. }
  394. }
  395. bool CConnection::readAndDecodeRect(const Rect& r, int encoding,
  396. ModifiablePixelBuffer* pb)
  397. {
  398. if (!decoder.decodeRect(r, encoding, pb))
  399. return false;
  400. decoder.flush();
  401. return true;
  402. }
  403. void CConnection::framebufferUpdateStart()
  404. {
  405. CMsgHandler::framebufferUpdateStart();
  406. assert(framebuffer != NULL);
  407. // Note: This might not be true if continuous updates are supported
  408. pendingUpdate = false;
  409. requestNewUpdate();
  410. }
  411. void CConnection::framebufferUpdateEnd()
  412. {
  413. decoder.flush();
  414. CMsgHandler::framebufferUpdateEnd();
  415. // A format change has been scheduled and we are now past the update
  416. // with the old format. Time to active the new one.
  417. if (pendingPFChange && !continuousUpdates) {
  418. server.setPF(pendingPF);
  419. pendingPFChange = false;
  420. }
  421. if (firstUpdate) {
  422. if (server.supportsContinuousUpdates) {
  423. vlog.info("Enabling continuous updates");
  424. continuousUpdates = true;
  425. writer()->writeEnableContinuousUpdates(true, 0, 0,
  426. server.width(),
  427. server.height());
  428. }
  429. firstUpdate = false;
  430. }
  431. }
  432. bool CConnection::dataRect(const Rect& r, int encoding)
  433. {
  434. return decoder.decodeRect(r, encoding, framebuffer);
  435. }
  436. void CConnection::serverCutText(const char* str)
  437. {
  438. hasLocalClipboard = false;
  439. strFree(serverClipboard);
  440. serverClipboard = NULL;
  441. serverClipboard = strDup(latin1ToUTF8(str).c_str());
  442. handleClipboardAnnounce(true);
  443. }
  444. void CConnection::handleClipboardCaps(uint32_t flags,
  445. const uint32_t* lengths)
  446. {
  447. uint32_t sizes[] = { 0 };
  448. CMsgHandler::handleClipboardCaps(flags, lengths);
  449. writer()->writeClipboardCaps(rfb::clipboardUTF8 |
  450. rfb::clipboardRequest |
  451. rfb::clipboardPeek |
  452. rfb::clipboardNotify |
  453. rfb::clipboardProvide,
  454. sizes);
  455. }
  456. void CConnection::handleClipboardRequest(uint32_t flags)
  457. {
  458. if (!(flags & rfb::clipboardUTF8)) {
  459. vlog.debug("Ignoring clipboard request for unsupported formats 0x%x", flags);
  460. return;
  461. }
  462. if (!hasLocalClipboard) {
  463. vlog.debug("Ignoring unexpected clipboard request");
  464. return;
  465. }
  466. handleClipboardRequest();
  467. }
  468. void CConnection::handleClipboardPeek()
  469. {
  470. if (server.clipboardFlags() & rfb::clipboardNotify)
  471. writer()->writeClipboardNotify(hasLocalClipboard ? rfb::clipboardUTF8 : 0);
  472. }
  473. void CConnection::handleClipboardNotify(uint32_t flags)
  474. {
  475. strFree(serverClipboard);
  476. serverClipboard = NULL;
  477. if (flags & rfb::clipboardUTF8) {
  478. hasLocalClipboard = false;
  479. handleClipboardAnnounce(true);
  480. } else {
  481. handleClipboardAnnounce(false);
  482. }
  483. }
  484. void CConnection::handleClipboardProvide(uint32_t flags,
  485. const size_t* lengths,
  486. const uint8_t* const* data)
  487. {
  488. if (!(flags & rfb::clipboardUTF8)) {
  489. vlog.debug("Ignoring clipboard provide with unsupported formats 0x%x", flags);
  490. return;
  491. }
  492. strFree(serverClipboard);
  493. serverClipboard = NULL;
  494. std::string filtered(convertLF((const char*)data[0], lengths[0]));
  495. serverClipboard = strDup(filtered.c_str());
  496. // FIXME: Should probably verify that this data was actually requested
  497. handleClipboardData(serverClipboard);
  498. }
  499. void CConnection::authSuccess()
  500. {
  501. }
  502. void CConnection::initDone()
  503. {
  504. }
  505. void CConnection::resizeFramebuffer()
  506. {
  507. assert(false);
  508. }
  509. void CConnection::handleClipboardRequest()
  510. {
  511. }
  512. void CConnection::handleClipboardAnnounce(bool /*available*/)
  513. {
  514. }
  515. void CConnection::handleClipboardData(const char* /*data*/)
  516. {
  517. }
  518. void CConnection::requestClipboard()
  519. {
  520. if (serverClipboard != NULL) {
  521. handleClipboardData(serverClipboard);
  522. return;
  523. }
  524. if (server.clipboardFlags() & rfb::clipboardRequest)
  525. writer()->writeClipboardRequest(rfb::clipboardUTF8);
  526. }
  527. void CConnection::announceClipboard(bool available)
  528. {
  529. hasLocalClipboard = available;
  530. unsolicitedClipboardAttempt = false;
  531. // Attempt an unsolicited transfer?
  532. if (available &&
  533. (server.clipboardSize(rfb::clipboardUTF8) > 0) &&
  534. (server.clipboardFlags() & rfb::clipboardProvide)) {
  535. vlog.debug("Attempting unsolicited clipboard transfer...");
  536. unsolicitedClipboardAttempt = true;
  537. handleClipboardRequest();
  538. return;
  539. }
  540. if (server.clipboardFlags() & rfb::clipboardNotify) {
  541. writer()->writeClipboardNotify(available ? rfb::clipboardUTF8 : 0);
  542. return;
  543. }
  544. if (available)
  545. handleClipboardRequest();
  546. }
  547. void CConnection::sendClipboardData(const char* data)
  548. {
  549. if (server.clipboardFlags() & rfb::clipboardProvide) {
  550. std::string filtered(convertCRLF(data));
  551. size_t sizes[1] = { filtered.size() + 1 };
  552. const uint8_t* data[1] = { (const uint8_t*)filtered.c_str() };
  553. if (unsolicitedClipboardAttempt) {
  554. unsolicitedClipboardAttempt = false;
  555. if (sizes[0] > server.clipboardSize(rfb::clipboardUTF8)) {
  556. vlog.debug("Clipboard was too large for unsolicited clipboard transfer");
  557. if (server.clipboardFlags() & rfb::clipboardNotify)
  558. writer()->writeClipboardNotify(rfb::clipboardUTF8);
  559. return;
  560. }
  561. }
  562. writer()->writeClipboardProvide(rfb::clipboardUTF8, sizes, data);
  563. } else {
  564. std::string latin1(utf8ToLatin1(data));
  565. writer()->writeClientCutText(latin1.c_str());
  566. }
  567. }
  568. void CConnection::refreshFramebuffer()
  569. {
  570. forceNonincremental = true;
  571. // Without continuous updates we have to make sure we only have a
  572. // single update in flight, so we'll have to wait to do the refresh
  573. if (continuousUpdates)
  574. requestNewUpdate();
  575. }
  576. void CConnection::setPreferredEncoding(int encoding)
  577. {
  578. if (preferredEncoding == encoding)
  579. return;
  580. preferredEncoding = encoding;
  581. encodingChange = true;
  582. }
  583. int CConnection::getPreferredEncoding()
  584. {
  585. return preferredEncoding;
  586. }
  587. void CConnection::setCompressLevel(int level)
  588. {
  589. if (compressLevel == level)
  590. return;
  591. compressLevel = level;
  592. encodingChange = true;
  593. }
  594. void CConnection::setQualityLevel(int level)
  595. {
  596. if (qualityLevel == level)
  597. return;
  598. qualityLevel = level;
  599. encodingChange = true;
  600. }
  601. void CConnection::setPF(const PixelFormat& pf)
  602. {
  603. if (server.pf().equal(pf) && !formatChange)
  604. return;
  605. nextPF = pf;
  606. formatChange = true;
  607. }
  608. void CConnection::fence(uint32_t flags, unsigned len, const char data[])
  609. {
  610. CMsgHandler::fence(flags, len, data);
  611. if (!(flags & fenceFlagRequest))
  612. return;
  613. // We cannot guarantee any synchronisation at this level
  614. flags = 0;
  615. writer()->writeFence(flags, len, data);
  616. }
  617. // requestNewUpdate() requests an update from the server, having set the
  618. // format and encoding appropriately.
  619. void CConnection::requestNewUpdate()
  620. {
  621. if (formatChange && !pendingPFChange) {
  622. /* Catch incorrect requestNewUpdate calls */
  623. assert(!pendingUpdate || continuousUpdates);
  624. // We have to make sure we switch the internal format at a safe
  625. // time. For continuous updates we temporarily disable updates and
  626. // look for a EndOfContinuousUpdates message to see when to switch.
  627. // For classical updates we just got a new update right before this
  628. // function was called, so we need to make sure we finish that
  629. // update before we can switch.
  630. pendingPFChange = true;
  631. pendingPF = nextPF;
  632. if (continuousUpdates)
  633. writer()->writeEnableContinuousUpdates(false, 0, 0, 0, 0);
  634. writer()->writeSetPixelFormat(pendingPF);
  635. if (continuousUpdates)
  636. writer()->writeEnableContinuousUpdates(true, 0, 0,
  637. server.width(),
  638. server.height());
  639. formatChange = false;
  640. }
  641. if (encodingChange) {
  642. updateEncodings();
  643. encodingChange = false;
  644. }
  645. if (forceNonincremental || !continuousUpdates) {
  646. pendingUpdate = true;
  647. writer()->writeFramebufferUpdateRequest(Rect(0, 0,
  648. server.width(),
  649. server.height()),
  650. !forceNonincremental);
  651. }
  652. forceNonincremental = false;
  653. }
  654. // Ask for encodings based on which decoders are supported. Assumes higher
  655. // encoding numbers are more desirable.
  656. void CConnection::updateEncodings()
  657. {
  658. std::list<uint32_t> encodings;
  659. if (supportsLocalCursor) {
  660. encodings.push_back(pseudoEncodingCursorWithAlpha);
  661. encodings.push_back(pseudoEncodingVMwareCursor);
  662. encodings.push_back(pseudoEncodingCursor);
  663. encodings.push_back(pseudoEncodingXCursor);
  664. }
  665. if (supportsCursorPosition) {
  666. encodings.push_back(pseudoEncodingVMwareCursorPosition);
  667. }
  668. if (supportsDesktopResize) {
  669. encodings.push_back(pseudoEncodingDesktopSize);
  670. encodings.push_back(pseudoEncodingExtendedDesktopSize);
  671. }
  672. if (supportsLEDState) {
  673. encodings.push_back(pseudoEncodingLEDState);
  674. encodings.push_back(pseudoEncodingVMwareLEDState);
  675. }
  676. encodings.push_back(pseudoEncodingDesktopName);
  677. encodings.push_back(pseudoEncodingLastRect);
  678. encodings.push_back(pseudoEncodingExtendedClipboard);
  679. encodings.push_back(pseudoEncodingContinuousUpdates);
  680. encodings.push_back(pseudoEncodingFence);
  681. encodings.push_back(pseudoEncodingQEMUKeyEvent);
  682. if (Decoder::supported(preferredEncoding)) {
  683. encodings.push_back(preferredEncoding);
  684. }
  685. encodings.push_back(encodingCopyRect);
  686. for (int i = encodingMax; i >= 0; i--) {
  687. if ((i != preferredEncoding) && Decoder::supported(i))
  688. encodings.push_back(i);
  689. }
  690. if (compressLevel >= 0 && compressLevel <= 9)
  691. encodings.push_back(pseudoEncodingCompressLevel0 + compressLevel);
  692. if (qualityLevel >= 0 && qualityLevel <= 9)
  693. encodings.push_back(pseudoEncodingQualityLevel0 + qualityLevel);
  694. writer()->writeSetEncodings(encodings);
  695. }