blob: de093964dd5daeab647ad3c1b9039f66f578acea [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);
Pierre Ossman34e62f32009-03-20 21:46:12 +0000193
194 os->writeU8(cp->screenLayout.num_screens());
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000195 os->pad(3);
Pierre Ossman34e62f32009-03-20 21:46:12 +0000196
197 ScreenSet::const_iterator iter;
198 for (iter = cp->screenLayout.begin();iter != cp->screenLayout.end();++iter) {
199 os->writeU32(iter->id);
200 os->writeU16(iter->dimensions.tl.x);
201 os->writeU16(iter->dimensions.tl.y);
202 os->writeU16(iter->dimensions.width());
203 os->writeU16(iter->dimensions.height());
204 os->writeU32(iter->flags);
205 }
206
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000207 needExtendedDesktopSize = false;
208 }
209
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000210 if (needSetDesktopSize) {
211 if (!cp->supportsDesktopResize)
212 throw Exception("Client does not support desktop resize");
213 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
214 throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
215 os->writeS16(0);
216 os->writeS16(0);
217 os->writeU16(cp->width);
218 os->writeU16(cp->height);
219 os->writeU32(pseudoEncodingDesktopSize);
220 needSetDesktopSize = false;
221 }
222
Peter Åstrandc39e0782009-01-15 12:21:42 +0000223 if (needSetDesktopName) {
224 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
225 throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
226 os->writeS16(0);
227 os->writeS16(0);
228 os->writeU16(0);
229 os->writeU16(0);
230 os->writeU32(pseudoEncodingDesktopName);
231 os->writeString(cp->name());
232 needSetDesktopName = false;
233 }
234
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000235 if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
236 throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
237 "nRects out of sync");
238 if (os == updateOS) {
239 os = realOS;
240 startMsg(msgTypeFramebufferUpdate);
241 os->pad(1);
242 os->writeU16(nRectsInUpdate);
243 os->writeBytes(updateOS->data(), updateOS->length());
244 updateOS->clear();
245 }
246
247 updatesSent++;
248 endMsg();
249}
250
251bool SMsgWriterV3::needFakeUpdate()
252{
Peter Åstrandc39e0782009-01-15 12:21:42 +0000253 return wsccb || needSetDesktopSize || needSetDesktopName;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000254}
255
256void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
257{
258 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
259 throw Exception("SMsgWriterV3::startRect: nRects out of sync");
260
261 currentEncoding = encoding;
262 lenBeforeRect = os->length();
263 if (encoding != encodingCopyRect)
264 rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
265
266 os->writeS16(r.tl.x);
267 os->writeS16(r.tl.y);
268 os->writeU16(r.width());
269 os->writeU16(r.height());
270 os->writeU32(encoding);
271}
272
273void SMsgWriterV3::endRect()
274{
275 if (currentEncoding <= encodingMax) {
276 bytesSent[currentEncoding] += os->length() - lenBeforeRect;
277 rectsSent[currentEncoding]++;
278 }
279}