blob: 3d51060f73606d617063a867c0706abd2be9b0b6 [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) {
116 case encodingTight:
117 case encodingZRLE:
118 case encodingHextile:
119 break;
120 default:
121 if ((i != preferredEncoding) && Decoder::supported(i))
122 encodings[nEncodings++] = i;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000123 }
124 }
Pierre Ossman090e7d62009-03-12 10:16:07 +0000125
Pierre Ossmana22459d2014-03-17 14:42:10 +0100126 if (cp->compressLevel >= 0 && cp->compressLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000127 encodings[nEncodings++] = pseudoEncodingCompressLevel0 + cp->compressLevel;
Pierre Ossmana22459d2014-03-17 14:42:10 +0100128 if (cp->qualityLevel >= 0 && cp->qualityLevel <= 9)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000129 encodings[nEncodings++] = pseudoEncodingQualityLevel0 + cp->qualityLevel;
130
131 writeSetEncodings(nEncodings, encodings);
132}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100133
134void CMsgWriter::writeSetDesktopSize(int width, int height,
135 const ScreenSet& layout)
136{
137 if (!cp->supportsSetDesktopSize)
138 throw Exception("Server does not support SetDesktopSize");
139
140 startMsg(msgTypeSetDesktopSize);
141 os->pad(1);
142
143 os->writeU16(width);
144 os->writeU16(height);
145
146 os->writeU8(layout.num_screens());
147 os->pad(1);
148
149 ScreenSet::const_iterator iter;
150 for (iter = layout.begin();iter != layout.end();++iter) {
151 os->writeU32(iter->id);
152 os->writeU16(iter->dimensions.tl.x);
153 os->writeU16(iter->dimensions.tl.y);
154 os->writeU16(iter->dimensions.width());
155 os->writeU16(iter->dimensions.height());
156 os->writeU32(iter->flags);
157 }
158
159 endMsg();
160}
161
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000162void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
163{
164 startMsg(msgTypeFramebufferUpdateRequest);
165 os->writeU8(incremental);
166 os->writeU16(r.tl.x);
167 os->writeU16(r.tl.y);
168 os->writeU16(r.width());
169 os->writeU16(r.height());
170 endMsg();
171}
172
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100173void CMsgWriter::writeEnableContinuousUpdates(bool enable,
174 int x, int y, int w, int h)
175{
176 if (!cp->supportsContinuousUpdates)
177 throw Exception("Server does not support continuous updates");
178
179 startMsg(msgTypeEnableContinuousUpdates);
180
181 os->writeU8(!!enable);
182
183 os->writeU16(x);
184 os->writeU16(y);
185 os->writeU16(w);
186 os->writeU16(h);
187
188 endMsg();
189}
190
191void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
192{
193 if (!cp->supportsFence)
194 throw Exception("Server does not support fences");
195 if (len > 64)
196 throw Exception("Too large fence payload");
197 if ((flags & ~fenceFlagsSupported) != 0)
198 throw Exception("Unknown fence flags");
199
200 startMsg(msgTypeClientFence);
201 os->pad(3);
202
203 os->writeU32(flags);
204
205 os->writeU8(len);
206 os->writeBytes(data, len);
207
208 endMsg();
209}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000210
211void CMsgWriter::keyEvent(rdr::U32 key, bool down)
212{
213 startMsg(msgTypeKeyEvent);
214 os->writeU8(down);
215 os->pad(2);
216 os->writeU32(key);
217 endMsg();
218}
219
220
221void CMsgWriter::pointerEvent(const Point& pos, int buttonMask)
222{
223 Point p(pos);
224 if (p.x < 0) p.x = 0;
225 if (p.y < 0) p.y = 0;
226 if (p.x >= cp->width) p.x = cp->width - 1;
227 if (p.y >= cp->height) p.y = cp->height - 1;
228
229 startMsg(msgTypePointerEvent);
230 os->writeU8(buttonMask);
231 os->writeU16(p.x);
232 os->writeU16(p.y);
233 endMsg();
234}
235
236
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000237void CMsgWriter::clientCutText(const char* str, rdr::U32 len)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000238{
239 startMsg(msgTypeClientCutText);
240 os->pad(3);
241 os->writeU32(len);
242 os->writeBytes(str, len);
243 endMsg();
244}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100245
246void CMsgWriter::startMsg(int type)
247{
248 os->writeU8(type);
249}
250
251void CMsgWriter::endMsg()
252{
253 os->flush();
254}