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.

CMsgWriter.cxx 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2014 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. #include <stdio.h>
  20. #include <rdr/OutStream.h>
  21. #include <rfb/msgTypes.h>
  22. #include <rfb/fenceTypes.h>
  23. #include <rfb/encodings.h>
  24. #include <rfb/qemuTypes.h>
  25. #include <rfb/Exception.h>
  26. #include <rfb/PixelFormat.h>
  27. #include <rfb/Rect.h>
  28. #include <rfb/ConnParams.h>
  29. #include <rfb/Decoder.h>
  30. #include <rfb/CMsgWriter.h>
  31. using namespace rfb;
  32. CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
  33. : cp(cp_), os(os_)
  34. {
  35. }
  36. CMsgWriter::~CMsgWriter()
  37. {
  38. }
  39. void CMsgWriter::writeClientInit(bool shared)
  40. {
  41. os->writeU8(shared);
  42. endMsg();
  43. }
  44. void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
  45. {
  46. startMsg(msgTypeSetPixelFormat);
  47. os->pad(3);
  48. pf.write(os);
  49. endMsg();
  50. }
  51. void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
  52. {
  53. startMsg(msgTypeSetEncodings);
  54. os->skip(1);
  55. os->writeU16(nEncodings);
  56. for (int i = 0; i < nEncodings; i++)
  57. os->writeU32(encodings[i]);
  58. endMsg();
  59. }
  60. // Ask for encodings based on which decoders are supported. Assumes higher
  61. // encoding numbers are more desirable.
  62. void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
  63. {
  64. int nEncodings = 0;
  65. rdr::U32 encodings[encodingMax+3];
  66. if (cp->supportsLocalCursor) {
  67. encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
  68. encodings[nEncodings++] = pseudoEncodingCursor;
  69. encodings[nEncodings++] = pseudoEncodingXCursor;
  70. }
  71. if (cp->supportsDesktopResize)
  72. encodings[nEncodings++] = pseudoEncodingDesktopSize;
  73. if (cp->supportsExtendedDesktopSize)
  74. encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
  75. if (cp->supportsDesktopRename)
  76. encodings[nEncodings++] = pseudoEncodingDesktopName;
  77. if (cp->supportsLEDState)
  78. encodings[nEncodings++] = pseudoEncodingLEDState;
  79. encodings[nEncodings++] = pseudoEncodingLastRect;
  80. encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
  81. encodings[nEncodings++] = pseudoEncodingFence;
  82. encodings[nEncodings++] = pseudoEncodingQEMUKeyEvent;
  83. if (Decoder::supported(preferredEncoding)) {
  84. encodings[nEncodings++] = preferredEncoding;
  85. }
  86. if (useCopyRect) {
  87. encodings[nEncodings++] = encodingCopyRect;
  88. }
  89. /*
  90. * Prefer encodings in this order:
  91. *
  92. * Tight, ZRLE, Hextile, *
  93. */
  94. if ((preferredEncoding != encodingTight) &&
  95. Decoder::supported(encodingTight))
  96. encodings[nEncodings++] = encodingTight;
  97. if ((preferredEncoding != encodingZRLE) &&
  98. Decoder::supported(encodingZRLE))
  99. encodings[nEncodings++] = encodingZRLE;
  100. if ((preferredEncoding != encodingHextile) &&
  101. Decoder::supported(encodingHextile))
  102. encodings[nEncodings++] = encodingHextile;
  103. // Remaining encodings
  104. for (int i = encodingMax; i >= 0; i--) {
  105. switch (i) {
  106. case encodingCopyRect:
  107. case encodingTight:
  108. case encodingZRLE:
  109. case encodingHextile:
  110. /* These have already been sent earlier */
  111. break;
  112. default:
  113. if ((i != preferredEncoding) && Decoder::supported(i))
  114. encodings[nEncodings++] = i;
  115. }
  116. }
  117. if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
  118. encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
  119. if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
  120. encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
  121. writeSetEncodings(nEncodings, encodings);
  122. }
  123. void CMsgWriter::writeSetDesktopSize(int width, int height,
  124. const ScreenSet& layout)
  125. {
  126. if (!cp->supportsSetDesktopSize)
  127. throw Exception("Server does not support SetDesktopSize");
  128. startMsg(msgTypeSetDesktopSize);
  129. os->pad(1);
  130. os->writeU16(width);
  131. os->writeU16(height);
  132. os->writeU8(layout.num_screens());
  133. os->pad(1);
  134. ScreenSet::const_iterator iter;
  135. for (iter = layout.begin();iter != layout.end();++iter) {
  136. os->writeU32(iter->id);
  137. os->writeU16(iter->dimensions.tl.x);
  138. os->writeU16(iter->dimensions.tl.y);
  139. os->writeU16(iter->dimensions.width());
  140. os->writeU16(iter->dimensions.height());
  141. os->writeU32(iter->flags);
  142. }
  143. endMsg();
  144. }
  145. void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
  146. {
  147. startMsg(msgTypeFramebufferUpdateRequest);
  148. os->writeU8(incremental);
  149. os->writeU16(r.tl.x);
  150. os->writeU16(r.tl.y);
  151. os->writeU16(r.width());
  152. os->writeU16(r.height());
  153. endMsg();
  154. }
  155. void CMsgWriter::writeEnableContinuousUpdates(bool enable,
  156. int x, int y, int w, int h)
  157. {
  158. if (!cp->supportsContinuousUpdates)
  159. throw Exception("Server does not support continuous updates");
  160. startMsg(msgTypeEnableContinuousUpdates);
  161. os->writeU8(!!enable);
  162. os->writeU16(x);
  163. os->writeU16(y);
  164. os->writeU16(w);
  165. os->writeU16(h);
  166. endMsg();
  167. }
  168. void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
  169. {
  170. if (!cp->supportsFence)
  171. throw Exception("Server does not support fences");
  172. if (len > 64)
  173. throw Exception("Too large fence payload");
  174. if ((flags & ~fenceFlagsSupported) != 0)
  175. throw Exception("Unknown fence flags");
  176. startMsg(msgTypeClientFence);
  177. os->pad(3);
  178. os->writeU32(flags);
  179. os->writeU8(len);
  180. os->writeBytes(data, len);
  181. endMsg();
  182. }
  183. void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
  184. {
  185. if (!cp->supportsQEMUKeyEvent || !keycode) {
  186. /* This event isn't meaningful without a valid keysym */
  187. if (!keysym)
  188. return;
  189. startMsg(msgTypeKeyEvent);
  190. os->writeU8(down);
  191. os->pad(2);
  192. os->writeU32(keysym);
  193. endMsg();
  194. } else {
  195. startMsg(msgTypeQEMUClientMessage);
  196. os->writeU8(qemuExtendedKeyEvent);
  197. os->writeU16(down);
  198. os->writeU32(keysym);
  199. os->writeU32(keycode);
  200. endMsg();
  201. }
  202. }
  203. void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
  204. {
  205. Point p(pos);
  206. if (p.x < 0) p.x = 0;
  207. if (p.y < 0) p.y = 0;
  208. if (p.x >= cp->width) p.x = cp->width - 1;
  209. if (p.y >= cp->height) p.y = cp->height - 1;
  210. startMsg(msgTypePointerEvent);
  211. os->writeU8(buttonMask);
  212. os->writeU16(p.x);
  213. os->writeU16(p.y);
  214. endMsg();
  215. }
  216. void CMsgWriter::writeClientCutText(const char* str, rdr::U32 len)
  217. {
  218. startMsg(msgTypeClientCutText);
  219. os->pad(3);
  220. os->writeU32(len);
  221. os->writeBytes(str, len);
  222. endMsg();
  223. }
  224. void CMsgWriter::startMsg(int type)
  225. {
  226. os->writeU8(type);
  227. }
  228. void CMsgWriter::endMsg()
  229. {
  230. os->flush();
  231. }