blob: 2ad3a79a96b85542d020faca0c399ffc6a7930fa [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 Ossman6b68f972017-02-19 15:51:19 +010077 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000078 if (cp->supportsDesktopResize)
79 encodings[nEncodings++] = pseudoEncodingDesktopSize;
Pierre Ossman49f88222009-03-20 13:02:50 +000080 if (cp->supportsExtendedDesktopSize)
81 encodings[nEncodings++] = pseudoEncodingExtendedDesktopSize;
Peter Åstrandc39e0782009-01-15 12:21:42 +000082 if (cp->supportsDesktopRename)
83 encodings[nEncodings++] = pseudoEncodingDesktopName;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000084
85 encodings[nEncodings++] = pseudoEncodingLastRect;
Pierre Ossmanc898d9a2011-11-14 16:22:23 +000086 encodings[nEncodings++] = pseudoEncodingContinuousUpdates;
Pierre Ossmanc754cce2011-11-14 15:44:11 +000087 encodings[nEncodings++] = pseudoEncodingFence;
88
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000089 if (Decoder::supported(preferredEncoding)) {
90 encodings[nEncodings++] = preferredEncoding;
91 }
Pierre Ossmanc754cce2011-11-14 15:44:11 +000092
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000093 if (useCopyRect) {
94 encodings[nEncodings++] = encodingCopyRect;
95 }
Pierre Ossman090e7d62009-03-12 10:16:07 +000096
97 /*
98 * Prefer encodings in this order:
99 *
100 * Tight, ZRLE, Hextile, *
101 */
102
103 if ((preferredEncoding != encodingTight) &&
104 Decoder::supported(encodingTight))
105 encodings[nEncodings++] = encodingTight;
106
107 if ((preferredEncoding != encodingZRLE) &&
108 Decoder::supported(encodingZRLE))
109 encodings[nEncodings++] = encodingZRLE;
110
111 if ((preferredEncoding != encodingHextile) &&
112 Decoder::supported(encodingHextile))
113 encodings[nEncodings++] = encodingHextile;
114
115 // Remaining encodings
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000116 for (int i = encodingMax; i >= 0; i--) {
Pierre Ossman090e7d62009-03-12 10:16:07 +0000117 switch (i) {
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100118 case encodingCopyRect:
Pierre Ossman090e7d62009-03-12 10:16:07 +0000119 case encodingTight:
120 case encodingZRLE:
121 case encodingHextile:
Pierre Ossmand704e4a2014-01-31 11:21:51 +0100122 /* These have already been sent earlier */
Pierre Ossman090e7d62009-03-12 10:16:07 +0000123 break;
124 default:
125 if ((i != preferredEncoding) && Decoder::supported(i))
126 encodings[nEncodings++] = i;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000127 }
128 }
Pierre Ossman090e7d62009-03-12 10:16:07 +0000129
Pierre Ossmana22459d2014-03-17 14:42:10 +0100130 if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000131 encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
Pierre Ossmana22459d2014-03-17 14:42:10 +0100132 if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000133 encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
134
135 writeSetEncodings(nEncodings, encodings);
136}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100137
138void CMsgWriter::writeSetDesktopSize(int width, int height,
139 const ScreenSet& layout)
140{
141 if (!cp->supportsSetDesktopSize)
142 throw Exception("Server does not support SetDesktopSize");
143
144 startMsg(msgTypeSetDesktopSize);
145 os->pad(1);
146
147 os->writeU16(width);
148 os->writeU16(height);
149
150 os->writeU8(layout.num_screens());
151 os->pad(1);
152
153 ScreenSet::const_iterator iter;
154 for (iter = layout.begin();iter != layout.end();++iter) {
155 os->writeU32(iter->id);
156 os->writeU16(iter->dimensions.tl.x);
157 os->writeU16(iter->dimensions.tl.y);
158 os->writeU16(iter->dimensions.width());
159 os->writeU16(iter->dimensions.height());
160 os->writeU32(iter->flags);
161 }
162
163 endMsg();
164}
165
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000166void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
167{
168 startMsg(msgTypeFramebufferUpdateRequest);
169 os->writeU8(incremental);
170 os->writeU16(r.tl.x);
171 os->writeU16(r.tl.y);
172 os->writeU16(r.width());
173 os->writeU16(r.height());
174 endMsg();
175}
176
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100177void CMsgWriter::writeEnableContinuousUpdates(bool enable,
178 int x, int y, int w, int h)
179{
180 if (!cp->supportsContinuousUpdates)
181 throw Exception("Server does not support continuous updates");
182
183 startMsg(msgTypeEnableContinuousUpdates);
184
185 os->writeU8(!!enable);
186
187 os->writeU16(x);
188 os->writeU16(y);
189 os->writeU16(w);
190 os->writeU16(h);
191
192 endMsg();
193}
194
195void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
196{
197 if (!cp->supportsFence)
198 throw Exception("Server does not support fences");
199 if (len > 64)
200 throw Exception("Too large fence payload");
201 if ((flags & ~fenceFlagsSupported) != 0)
202 throw Exception("Unknown fence flags");
203
204 startMsg(msgTypeClientFence);
205 os->pad(3);
206
207 os->writeU32(flags);
208
209 os->writeU8(len);
210 os->writeBytes(data, len);
211
212 endMsg();
213}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000214
215void CMsgWriter::keyEvent(rdr::U32 key, bool down)
216{
217 startMsg(msgTypeKeyEvent);
218 os->writeU8(down);
219 os->pad(2);
220 os->writeU32(key);
221 endMsg();
222}
223
224
225void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
226{
227 Point p(pos);
228 if (p.x < 0) p.x = 0;
229 if (p.y < 0) p.y = 0;
230 if (p.x >= cp->width) p.x = cp->width - 1;
231 if (p.y >= cp->height) p.y = cp->height - 1;
232
233 startMsg(msgTypePointerEvent);
234 os->writeU8(buttonMask);
235 os->writeU16(p.x);
236 os->writeU16(p.y);
237 endMsg();
238}
239
240
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000241void CMsgWriter::clientCutText(const char* str, rdr::U32 len)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000242{
243 startMsg(msgTypeClientCutText);
244 os->pad(3);
245 os->writeU32(len);
246 os->writeBytes(str, len);
247 endMsg();
248}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100249
250void CMsgWriter::startMsg(int type)
251{
252 os->writeU8(type);
253}
254
255void CMsgWriter::endMsg()
256{
257 os->flush();
258}