blob: 8576d8f1245750a740ff78910c203164a17cd985 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman7638e9c2014-01-16 13:12:40 +01002 * Copyright 2009-2014 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 */
19#include <stdio.h>
20#include <rdr/OutStream.h>
21#include <rfb/msgTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010022#include <rfb/fenceTypes.h>
Pierre Ossman316a3242014-01-15 12:40:20 +010023#include <rfb/encodings.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010024#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025#include <rfb/PixelFormat.h>
26#include <rfb/Rect.h>
27#include <rfb/ConnParams.h>
28#include <rfb/Decoder.h>
29#include <rfb/CMsgWriter.h>
30
31using namespace rfb;
32
33CMsgWriter::CMsgWriter(ConnParams* cp_, rdr::OutStream* os_)
34 : cp(cp_), os(os_)
35{
36}
37
38CMsgWriter::~CMsgWriter()
39{
40}
41
Pierre Ossman7638e9c2014-01-16 13:12:40 +010042void CMsgWriter::writeClientInit(bool shared)
43{
44 os->writeU8(shared);
45 endMsg();
46}
47
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
49{
50 startMsg(msgTypeSetPixelFormat);
51 os->pad(3);
52 pf.write(os);
53 endMsg();
54}
55
56void CMsgWriter::writeSetEncodings(int nEncodings, rdr::U32* encodings)
57{
58 startMsg(msgTypeSetEncodings);
59 os->skip(1);
60 os->writeU16(nEncodings);
61 for (int i = 0; i < nEncodings; i++)
62 os->writeU32(encodings[i]);
63 endMsg();
64}
65
66// Ask for encodings based on which decoders are supported. Assumes higher
67// encoding numbers are more desirable.
68
69void CMsgWriter::writeSetEncodings(int preferredEncoding, bool useCopyRect)
70{
71 int nEncodings = 0;
72 rdr::U32 encodings[encodingMax+3];
Pierre Ossmanc754cce2011-11-14 15:44:11 +000073
Pierre Ossman6b68f972017-02-19 15:51:19 +010074 if (cp->supportsLocalCursor) {
75 encodings[nEncodings++] = pseudoEncodingXCursor;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000076 encodings[nEncodings++] = pseudoEncodingCursor;
Pierre Ossmana4c0aac2017-02-19 15:50:29 +010077 encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
Pierre Ossman6b68f972017-02-19 15:51:19 +010078 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000079 if (cp->supportsDesktopResize)
80 encodings[nEncodings++] = pseudoEncodingDesktopSize;
Pierre Ossman49f88222009-03-20 13:02:50 +000081 if (cp->supportsExtendedDesktopSize)
82 encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
Peter Åstrandc39e0782009-01-15 12:21:42 +000083 if (cp->supportsDesktopRename)
84 encodings[nEncodings++] = pseudoEncodingDesktopName;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000085
86 encodings[nEncodings++] = pseudoEncodingLastRect;
Pierre Ossmanc898d9a2011-11-14 16:22:23 +000087 encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000088 encodings[nEncodings++] = pseudoEncodingFence;
89
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000090 if (Decoder::supported(preferredEncoding)) {
91 encodings[nEncodings++] = preferredEncoding;
92 }
Pierre Ossmanc754cce2011-11-14 15:44:11 +000093
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000094 if (useCopyRect) {
95 encodings[nEncodings++] = encodingCopyRect;
96 }
Pierre Ossman090e7d62009-03-12 10:16:07 +000097
98 /*
99 * Prefer encodings in this order:
100 *
101 * Tight, ZRLE, Hextile, *
102 */
103
104 if ((preferredEncoding != encodingTight) &&
105 Decoder::supported(encodingTight))
106 encodings[nEncodings++] = encodingTight;
107
108 if ((preferredEncoding != encodingZRLE) &&
109 Decoder::supported(encodingZRLE))
110 encodings[nEncodings++] = encodingZRLE;
111
112 if ((preferredEncoding != encodingHextile) &&
113 Decoder::supported(encodingHextile))
114 encodings[nEncodings++] = encodingHextile;
115
116 // Remaining encodings
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000117 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman090e7d62009-03-12 10:16:07 +0000118 switch (i) {
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100119 case encodingCopyRect:
Pierre Ossman090e7d62009-03-12 10:16:07 +0000120 case encodingTight:
121 case encodingZRLE:
122 case encodingHextile:
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100123 /* These have already been sent earlier */
Pierre Ossman090e7d62009-03-12 10:16:07 +0000124 break;
125 default:
126 if ((i != preferredEncoding) && Decoder::supported(i))
127 encodings[nEncodings++] = i;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000128 }
129 }
Pierre Ossman090e7d62009-03-12 10:16:07 +0000130
Pierre Ossmana22459d2014-03-17 14:42:10 +0100131 if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000132 encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
Pierre Ossmana22459d2014-03-17 14:42:10 +0100133 if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000134 encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
135
136 writeSetEncodings(nEncodings, encodings);
137}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100138
139void CMsgWriter::writeSetDesktopSize(int width, int height,
140 const ScreenSet& layout)
141{
142 if (!cp->supportsSetDesktopSize)
143 throw Exception("Server does not support SetDesktopSize");
144
145 startMsg(msgTypeSetDesktopSize);
146 os->pad(1);
147
148 os->writeU16(width);
149 os->writeU16(height);
150
151 os->writeU8(layout.num_screens());
152 os->pad(1);
153
154 ScreenSet::const_iterator iter;
155 for (iter = layout.begin();iter != layout.end();++iter) {
156 os->writeU32(iter->id);
157 os->writeU16(iter->dimensions.tl.x);
158 os->writeU16(iter->dimensions.tl.y);
159 os->writeU16(iter->dimensions.width());
160 os->writeU16(iter->dimensions.height());
161 os->writeU32(iter->flags);
162 }
163
164 endMsg();
165}
166
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000167void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
168{
169 startMsg(msgTypeFramebufferUpdateRequest);
170 os->writeU8(incremental);
171 os->writeU16(r.tl.x);
172 os->writeU16(r.tl.y);
173 os->writeU16(r.width());
174 os->writeU16(r.height());
175 endMsg();
176}
177
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100178void CMsgWriter::writeEnableContinuousUpdates(bool enable,
179 int x, int y, int w, int h)
180{
181 if (!cp->supportsContinuousUpdates)
182 throw Exception("Server does not support continuous updates");
183
184 startMsg(msgTypeEnableContinuousUpdates);
185
186 os->writeU8(!!enable);
187
188 os->writeU16(x);
189 os->writeU16(y);
190 os->writeU16(w);
191 os->writeU16(h);
192
193 endMsg();
194}
195
196void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
197{
198 if (!cp->supportsFence)
199 throw Exception("Server does not support fences");
200 if (len > 64)
201 throw Exception("Too large fence payload");
202 if ((flags & ~fenceFlagsSupported) != 0)
203 throw Exception("Unknown fence flags");
204
205 startMsg(msgTypeClientFence);
206 os->pad(3);
207
208 os->writeU32(flags);
209
210 os->writeU8(len);
211 os->writeBytes(data, len);
212
213 endMsg();
214}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000215
216void CMsgWriter::keyEvent(rdr::U32 key, bool down)
217{
218 startMsg(msgTypeKeyEvent);
219 os->writeU8(down);
220 os->pad(2);
221 os->writeU32(key);
222 endMsg();
223}
224
225
226void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
227{
228 Point p(pos);
229 if (p.x < 0) p.x = 0;
230 if (p.y < 0) p.y = 0;
231 if (p.x >= cp->width) p.x = cp->width - 1;
232 if (p.y >= cp->height) p.y = cp->height - 1;
233
234 startMsg(msgTypePointerEvent);
235 os->writeU8(buttonMask);
236 os->writeU16(p.x);
237 os->writeU16(p.y);
238 endMsg();
239}
240
241
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000242void CMsgWriter::clientCutText(const char* str, rdr::U32 len)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000243{
244 startMsg(msgTypeClientCutText);
245 os->pad(3);
246 os->writeU32(len);
247 os->writeBytes(str, len);
248 endMsg();
249}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100250
251void CMsgWriter::startMsg(int type)
252{
253 os->writeU8(type);
254}
255
256void CMsgWriter::endMsg()
257{
258 os->flush();
259}