blob: 7a89a934051d4e33c467f4dcd04594551522efba [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) {
Pierre Ossmana4c0aac2017-02-19 15:50:29 +010075 encodings[nEncodings++] = pseudoEncodingCursorWithAlpha;
Pierre Ossmana8ecb792017-08-16 16:25:24 +020076 encodings[nEncodings++] = pseudoEncodingCursor;
77 encodings[nEncodings++] = pseudoEncodingXCursor;
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 Ossman2fa63f82016-12-05 15:26:21 +010085 if (cp->supportsLEDState)
86 encodings[nEncodings++] = pseudoEncodingLEDState;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000087
88 encodings[nEncodings++] = pseudoEncodingLastRect;
Pierre Ossmanc898d9a2011-11-14 16:22:23 +000089 encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000090 encodings[nEncodings++] = pseudoEncodingFence;
91
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000092 if (Decoder::supported(preferredEncoding)) {
93 encodings[nEncodings++] = preferredEncoding;
94 }
Pierre Ossmanc754cce2011-11-14 15:44:11 +000095
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000096 if (useCopyRect) {
97 encodings[nEncodings++] = encodingCopyRect;
98 }
Pierre Ossman090e7d62009-03-12 10:16:07 +000099
100 /*
101 * Prefer encodings in this order:
102 *
103 * Tight, ZRLE, Hextile, *
104 */
105
106 if ((preferredEncoding != encodingTight) &&
107 Decoder::supported(encodingTight))
108 encodings[nEncodings++] = encodingTight;
109
110 if ((preferredEncoding != encodingZRLE) &&
111 Decoder::supported(encodingZRLE))
112 encodings[nEncodings++] = encodingZRLE;
113
114 if ((preferredEncoding != encodingHextile) &&
115 Decoder::supported(encodingHextile))
116 encodings[nEncodings++] = encodingHextile;
117
118 // Remaining encodings
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000119 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman090e7d62009-03-12 10:16:07 +0000120 switch (i) {
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100121 case encodingCopyRect:
Pierre Ossman090e7d62009-03-12 10:16:07 +0000122 case encodingTight:
123 case encodingZRLE:
124 case encodingHextile:
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100125 /* These have already been sent earlier */
Pierre Ossman090e7d62009-03-12 10:16:07 +0000126 break;
127 default:
128 if ((i != preferredEncoding) && Decoder::supported(i))
129 encodings[nEncodings++] = i;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000130 }
131 }
Pierre Ossman090e7d62009-03-12 10:16:07 +0000132
Pierre Ossmana22459d2014-03-17 14:42:10 +0100133 if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000134 encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
Pierre Ossmana22459d2014-03-17 14:42:10 +0100135 if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000136 encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
137
138 writeSetEncodings(nEncodings, encodings);
139}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100140
141void CMsgWriter::writeSetDesktopSize(int width, int height,
142 const ScreenSet& layout)
143{
144 if (!cp->supportsSetDesktopSize)
145 throw Exception("Server does not support SetDesktopSize");
146
147 startMsg(msgTypeSetDesktopSize);
148 os->pad(1);
149
150 os->writeU16(width);
151 os->writeU16(height);
152
153 os->writeU8(layout.num_screens());
154 os->pad(1);
155
156 ScreenSet::const_iterator iter;
157 for (iter = layout.begin();iter != layout.end();++iter) {
158 os->writeU32(iter->id);
159 os->writeU16(iter->dimensions.tl.x);
160 os->writeU16(iter->dimensions.tl.y);
161 os->writeU16(iter->dimensions.width());
162 os->writeU16(iter->dimensions.height());
163 os->writeU32(iter->flags);
164 }
165
166 endMsg();
167}
168
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
170{
171 startMsg(msgTypeFramebufferUpdateRequest);
172 os->writeU8(incremental);
173 os->writeU16(r.tl.x);
174 os->writeU16(r.tl.y);
175 os->writeU16(r.width());
176 os->writeU16(r.height());
177 endMsg();
178}
179
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100180void CMsgWriter::writeEnableContinuousUpdates(bool enable,
181 int x, int y, int w, int h)
182{
183 if (!cp->supportsContinuousUpdates)
184 throw Exception("Server does not support continuous updates");
185
186 startMsg(msgTypeEnableContinuousUpdates);
187
188 os->writeU8(!!enable);
189
190 os->writeU16(x);
191 os->writeU16(y);
192 os->writeU16(w);
193 os->writeU16(h);
194
195 endMsg();
196}
197
198void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
199{
200 if (!cp->supportsFence)
201 throw Exception("Server does not support fences");
202 if (len > 64)
203 throw Exception("Too large fence payload");
204 if ((flags & ~fenceFlagsSupported) != 0)
205 throw Exception("Unknown fence flags");
206
207 startMsg(msgTypeClientFence);
208 os->pad(3);
209
210 os->writeU32(flags);
211
212 os->writeU8(len);
213 os->writeBytes(data, len);
214
215 endMsg();
216}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000217
218void CMsgWriter::keyEvent(rdr::U32 key, bool down)
219{
220 startMsg(msgTypeKeyEvent);
221 os->writeU8(down);
222 os->pad(2);
223 os->writeU32(key);
224 endMsg();
225}
226
227
228void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
229{
230 Point p(pos);
231 if (p.x < 0) p.x = 0;
232 if (p.y < 0) p.y = 0;
233 if (p.x >= cp->width) p.x = cp->width - 1;
234 if (p.y >= cp->height) p.y = cp->height - 1;
235
236 startMsg(msgTypePointerEvent);
237 os->writeU8(buttonMask);
238 os->writeU16(p.x);
239 os->writeU16(p.y);
240 endMsg();
241}
242
243
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000244void CMsgWriter::clientCutText(const char* str, rdr::U32 len)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000245{
246 startMsg(msgTypeClientCutText);
247 os->pad(3);
248 os->writeU32(len);
249 os->writeBytes(str, len);
250 endMsg();
251}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100252
253void CMsgWriter::startMsg(int type)
254{
255 os->writeU8(type);
256}
257
258void CMsgWriter::endMsg()
259{
260 os->flush();
261}