blob: ca6f3f03aa8208fed68a06b36c60187c4f648ef0 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossmanc5e25602009-03-20 12:59:05 +00002 * Copyright 2009 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 <rdr/OutStream.h>
20#include <rdr/MemOutStream.h>
21#include <rfb/msgTypes.h>
Pierre Ossmanc5e25602009-03-20 12:59:05 +000022#include <rfb/screenTypes.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rfb/Exception.h>
24#include <rfb/ConnParams.h>
25#include <rfb/SMsgWriterV3.h>
26
27using namespace rfb;
28
29SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
30 : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0),
31 nRectsInHeader(0), wsccb(0),
Peter Åstrandc39e0782009-01-15 12:21:42 +000032 needSetDesktopSize(false), needSetDesktopName(false)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000033{
34}
35
36SMsgWriterV3::~SMsgWriterV3()
37{
38 delete updateOS;
39}
40
41void SMsgWriterV3::writeServerInit()
42{
43 os->writeU16(cp->width);
44 os->writeU16(cp->height);
45 cp->pf().write(os);
46 os->writeString(cp->name());
47 endMsg();
48}
49
50void SMsgWriterV3::startMsg(int type)
51{
52 if (os != realOS)
53 throw Exception("startMsg called while writing an update?");
54
55 os->writeU8(type);
56}
57
58void SMsgWriterV3::endMsg()
59{
60 os->flush();
61}
62
63bool SMsgWriterV3::writeSetDesktopSize() {
64 if (!cp->supportsDesktopResize) return false;
65 needSetDesktopSize = true;
66 return true;
67}
68
Pierre Ossmanc5e25602009-03-20 12:59:05 +000069bool SMsgWriterV3::writeExtendedDesktopSize(rdr::U16 error) {
70 if (!cp->supportsExtendedDesktopSize) return false;
71 if (error == resultUnsolicited)
72 needExtendedDesktopSize = true;
73 else
74 edsErrors.push_back(error);
75 return true;
76}
77
Peter Åstrandc39e0782009-01-15 12:21:42 +000078bool SMsgWriterV3::writeSetDesktopName() {
79 if (!cp->supportsDesktopRename) return false;
80 needSetDesktopName = true;
81 return true;
82}
83
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000084void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
85{
86 wsccb = cb;
87}
88
89void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
90 void* data, void* mask)
91{
92 if (!wsccb) return;
93 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
94 throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
95 os->writeS16(hotspot.x);
96 os->writeS16(hotspot.y);
97 os->writeU16(width);
98 os->writeU16(height);
99 os->writeU32(pseudoEncodingCursor);
100 os->writeBytes(data, width * height * (cp->pf().bpp/8));
101 os->writeBytes(mask, (width+7)/8 * height);
102}
103
104void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
105 int hotspotY, void* data, void* mask)
106{
107 if (!wsccb) return;
108 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
109 throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
110 os->writeS16(hotspotX);
111 os->writeS16(hotspotY);
112 os->writeU16(width);
113 os->writeU16(height);
114 os->writeU32(pseudoEncodingXCursor);
115 // FIXME: We only support black and white cursors, currently. We
116 // could pass the correct color by using the pix0/pix1 values
117 // returned from getBitmap, in writeSetCursorCallback. However, we
118 // would then need to undo the conversion from rgb to Pixel that is
119 // done by FakeAllocColor.
120 if (width * height) {
121 os->writeU8(0);
122 os->writeU8(0);
123 os->writeU8(0);
124 os->writeU8(255);
125 os->writeU8(255);
126 os->writeU8(255);
127 os->writeBytes(data, (width+7)/8 * height);
128 os->writeBytes(mask, (width+7)/8 * height);
129 }
130}
131
132void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
133{
134 startMsg(msgTypeFramebufferUpdate);
135 os->pad(1);
136 if (wsccb) nRects++;
137 if (needSetDesktopSize) nRects++;
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000138 if (needExtendedDesktopSize) nRects++;
139 if (!edsErrors.empty()) nRects += edsErrors.size();
Peter Åstrandc39e0782009-01-15 12:21:42 +0000140 if (needSetDesktopName) nRects++;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000141 os->writeU16(nRects);
142 nRectsInUpdate = 0;
143 nRectsInHeader = nRects;
144 if (wsccb) {
145 wsccb->writeSetCursorCallback();
146 wsccb = 0;
147 }
148}
149
150void SMsgWriterV3::writeFramebufferUpdateStart()
151{
152 nRectsInUpdate = nRectsInHeader = 0;
153 if (!updateOS)
154 updateOS = new rdr::MemOutStream;
155 os = updateOS;
156}
157
158void SMsgWriterV3::writeFramebufferUpdateEnd()
159{
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000160 /* Start with responses to SetDesktopSize messages */
161 if (!edsErrors.empty()) {
162 std::list<rdr::U16>::const_iterator iter;
163
164 if (!cp->supportsExtendedDesktopSize)
165 throw Exception("Client does not support extended desktop resize");
166 if ((nRectsInUpdate += edsErrors.size()) > nRectsInHeader && nRectsInHeader)
167 throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
168
169 for (iter = edsErrors.begin();iter != edsErrors.end();iter++) {
170 os->writeU16(1);
171 os->writeU16(*iter);
172 os->writeU16(0);
173 os->writeU16(0);
174 os->writeU32(pseudoEncodingExtendedDesktopSize);
175 os->writeU8(0); // # screens
176 os->pad(3);
177 }
178
179 edsErrors.clear();
180 }
181
182 /* Send this before SetDesktopSize to make life easier on the clients */
183 if (needExtendedDesktopSize) {
184 if (!cp->supportsExtendedDesktopSize)
185 throw Exception("Client does not support extended desktop resize");
186 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
187 throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
188 os->writeU16(0);
189 os->writeU16(0);
190 os->writeU16(cp->width);
191 os->writeU16(cp->height);
192 os->writeU32(pseudoEncodingExtendedDesktopSize);
193 os->writeU8(1); // # screens
194 os->pad(3);
195 os->writeU32(1); // id
196 os->writeU16(0); // x-pos
197 os->writeU16(0); // y-pos
198 os->writeU16(cp->width); // width
199 os->writeU16(cp->height); // height
200 os->writeU32(0); // flags
201 needExtendedDesktopSize = false;
202 }
203
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000204 if (needSetDesktopSize) {
205 if (!cp->supportsDesktopResize)
206 throw Exception("Client does not support desktop resize");
207 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
208 throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
209 os->writeS16(0);
210 os->writeS16(0);
211 os->writeU16(cp->width);
212 os->writeU16(cp->height);
213 os->writeU32(pseudoEncodingDesktopSize);
214 needSetDesktopSize = false;
215 }
216
Peter Åstrandc39e0782009-01-15 12:21:42 +0000217 if (needSetDesktopName) {
218 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
219 throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
220 os->writeS16(0);
221 os->writeS16(0);
222 os->writeU16(0);
223 os->writeU16(0);
224 os->writeU32(pseudoEncodingDesktopName);
225 os->writeString(cp->name());
226 needSetDesktopName = false;
227 }
228
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000229 if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
230 throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
231 "nRects out of sync");
232 if (os == updateOS) {
233 os = realOS;
234 startMsg(msgTypeFramebufferUpdate);
235 os->pad(1);
236 os->writeU16(nRectsInUpdate);
237 os->writeBytes(updateOS->data(), updateOS->length());
238 updateOS->clear();
239 }
240
241 updatesSent++;
242 endMsg();
243}
244
245bool SMsgWriterV3::needFakeUpdate()
246{
Peter Åstrandc39e0782009-01-15 12:21:42 +0000247 return wsccb || needSetDesktopSize || needSetDesktopName;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000248}
249
250void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
251{
252 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
253 throw Exception("SMsgWriterV3::startRect: nRects out of sync");
254
255 currentEncoding = encoding;
256 lenBeforeRect = os->length();
257 if (encoding != encodingCopyRect)
258 rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
259
260 os->writeS16(r.tl.x);
261 os->writeS16(r.tl.y);
262 os->writeU16(r.width());
263 os->writeU16(r.height());
264 os->writeU32(encoding);
265}
266
267void SMsgWriterV3::endRect()
268{
269 if (currentEncoding <= encodingMax) {
270 bytesSent[currentEncoding] += os->length() - lenBeforeRect;
271 rectsSent[currentEncoding]++;
272 }
273}