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