blob: a11579b676c2f93e8b974712127639b8eb0b1001 [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),
Adam Tkac0c6eff12009-04-02 15:44:23 +000031 nRectsInHeader(0), wsccb(0), needSetDesktopSize(false),
32 needExtendedDesktopSize(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 Ossman04e62db2009-03-23 16:57:07 +000069bool SMsgWriterV3::writeExtendedDesktopSize() {
Pierre Ossmanc5e25602009-03-20 12:59:05 +000070 if (!cp->supportsExtendedDesktopSize) return false;
Pierre Ossman04e62db2009-03-23 16:57:07 +000071 needExtendedDesktopSize = true;
72 return true;
73}
74
75bool SMsgWriterV3::writeExtendedDesktopSize(rdr::U16 reason, rdr::U16 result,
76 int fb_width, int fb_height,
77 const ScreenSet& layout) {
78 ExtendedDesktopSizeMsg msg;
79
80 if (!cp->supportsExtendedDesktopSize) return false;
81
82 msg.reason = reason;
83 msg.result = result;
84 msg.fb_width = fb_width;
85 msg.fb_height = fb_height;
86 msg.layout = layout;
87
88 extendedDesktopSizeMsgs.push_back(msg);
89
Pierre Ossmanc5e25602009-03-20 12:59:05 +000090 return true;
91}
92
Peter Åstrandc39e0782009-01-15 12:21:42 +000093bool SMsgWriterV3::writeSetDesktopName() {
94 if (!cp->supportsDesktopRename) return false;
95 needSetDesktopName = true;
96 return true;
97}
98
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000099void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
100{
101 wsccb = cb;
102}
103
104void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
105 void* data, void* mask)
106{
107 if (!wsccb) return;
108 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
109 throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
110 os->writeS16(hotspot.x);
111 os->writeS16(hotspot.y);
112 os->writeU16(width);
113 os->writeU16(height);
114 os->writeU32(pseudoEncodingCursor);
115 os->writeBytes(data, width * height * (cp->pf().bpp/8));
116 os->writeBytes(mask, (width+7)/8 * height);
117}
118
119void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
120 int hotspotY, void* data, void* mask)
121{
122 if (!wsccb) return;
123 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
124 throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
125 os->writeS16(hotspotX);
126 os->writeS16(hotspotY);
127 os->writeU16(width);
128 os->writeU16(height);
129 os->writeU32(pseudoEncodingXCursor);
130 // FIXME: We only support black and white cursors, currently. We
131 // could pass the correct color by using the pix0/pix1 values
132 // returned from getBitmap, in writeSetCursorCallback. However, we
133 // would then need to undo the conversion from rgb to Pixel that is
134 // done by FakeAllocColor.
135 if (width * height) {
136 os->writeU8(0);
137 os->writeU8(0);
138 os->writeU8(0);
139 os->writeU8(255);
140 os->writeU8(255);
141 os->writeU8(255);
142 os->writeBytes(data, (width+7)/8 * height);
143 os->writeBytes(mask, (width+7)/8 * height);
144 }
145}
146
147void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
148{
149 startMsg(msgTypeFramebufferUpdate);
150 os->pad(1);
151 if (wsccb) nRects++;
152 if (needSetDesktopSize) nRects++;
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000153 if (needExtendedDesktopSize) nRects++;
Pierre Ossman04e62db2009-03-23 16:57:07 +0000154 if (!extendedDesktopSizeMsgs.empty()) nRects += extendedDesktopSizeMsgs.size();
Peter Åstrandc39e0782009-01-15 12:21:42 +0000155 if (needSetDesktopName) nRects++;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000156 os->writeU16(nRects);
157 nRectsInUpdate = 0;
158 nRectsInHeader = nRects;
159 if (wsccb) {
160 wsccb->writeSetCursorCallback();
161 wsccb = 0;
162 }
163}
164
165void SMsgWriterV3::writeFramebufferUpdateStart()
166{
167 nRectsInUpdate = nRectsInHeader = 0;
168 if (!updateOS)
169 updateOS = new rdr::MemOutStream;
170 os = updateOS;
171}
172
173void SMsgWriterV3::writeFramebufferUpdateEnd()
174{
Pierre Ossman04e62db2009-03-23 16:57:07 +0000175 /* Start with specific ExtendedDesktopSize messages */
176 if (!extendedDesktopSizeMsgs.empty()) {
177 std::list<ExtendedDesktopSizeMsg>::const_iterator ri;
178 ScreenSet::const_iterator si;
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000179
180 if (!cp->supportsExtendedDesktopSize)
181 throw Exception("Client does not support extended desktop resize");
Pierre Ossman04e62db2009-03-23 16:57:07 +0000182 if ((nRectsInUpdate += extendedDesktopSizeMsgs.size()) > nRectsInHeader && nRectsInHeader)
183 throw Exception("SMsgWriterV3 SetDesktopSize reply: nRects out of sync");
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000184
Pierre Ossman04e62db2009-03-23 16:57:07 +0000185 for (ri = extendedDesktopSizeMsgs.begin();ri != extendedDesktopSizeMsgs.end();++ri) {
186 os->writeU16(ri->reason);
187 os->writeU16(ri->result);
188 os->writeU16(ri->fb_width);
189 os->writeU16(ri->fb_height);
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000190 os->writeU32(pseudoEncodingExtendedDesktopSize);
Pierre Ossman04e62db2009-03-23 16:57:07 +0000191
192 os->writeU8(ri->layout.num_screens());
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000193 os->pad(3);
Pierre Ossman04e62db2009-03-23 16:57:07 +0000194
195 for (si = ri->layout.begin();si != ri->layout.end();++si) {
196 os->writeU32(si->id);
197 os->writeU16(si->dimensions.tl.x);
198 os->writeU16(si->dimensions.tl.y);
199 os->writeU16(si->dimensions.width());
200 os->writeU16(si->dimensions.height());
201 os->writeU32(si->flags);
202 }
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000203 }
204
Pierre Ossman04e62db2009-03-23 16:57:07 +0000205 extendedDesktopSizeMsgs.clear();
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000206 }
207
208 /* Send this before SetDesktopSize to make life easier on the clients */
209 if (needExtendedDesktopSize) {
210 if (!cp->supportsExtendedDesktopSize)
211 throw Exception("Client does not support extended desktop resize");
212 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
213 throw Exception("SMsgWriterV3 setExtendedDesktopSize: nRects out of sync");
214 os->writeU16(0);
215 os->writeU16(0);
216 os->writeU16(cp->width);
217 os->writeU16(cp->height);
218 os->writeU32(pseudoEncodingExtendedDesktopSize);
Pierre Ossman34e62f32009-03-20 21:46:12 +0000219
220 os->writeU8(cp->screenLayout.num_screens());
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000221 os->pad(3);
Pierre Ossman34e62f32009-03-20 21:46:12 +0000222
223 ScreenSet::const_iterator iter;
224 for (iter = cp->screenLayout.begin();iter != cp->screenLayout.end();++iter) {
225 os->writeU32(iter->id);
226 os->writeU16(iter->dimensions.tl.x);
227 os->writeU16(iter->dimensions.tl.y);
228 os->writeU16(iter->dimensions.width());
229 os->writeU16(iter->dimensions.height());
230 os->writeU32(iter->flags);
231 }
232
Pierre Ossmanc5e25602009-03-20 12:59:05 +0000233 needExtendedDesktopSize = false;
234 }
235
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000236 if (needSetDesktopSize) {
237 if (!cp->supportsDesktopResize)
238 throw Exception("Client does not support desktop resize");
239 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
240 throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
241 os->writeS16(0);
242 os->writeS16(0);
243 os->writeU16(cp->width);
244 os->writeU16(cp->height);
245 os->writeU32(pseudoEncodingDesktopSize);
246 needSetDesktopSize = false;
247 }
248
Peter Åstrandc39e0782009-01-15 12:21:42 +0000249 if (needSetDesktopName) {
250 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
251 throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
252 os->writeS16(0);
253 os->writeS16(0);
254 os->writeU16(0);
255 os->writeU16(0);
256 os->writeU32(pseudoEncodingDesktopName);
257 os->writeString(cp->name());
258 needSetDesktopName = false;
259 }
260
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000261 if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
262 throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
263 "nRects out of sync");
264 if (os == updateOS) {
265 os = realOS;
266 startMsg(msgTypeFramebufferUpdate);
267 os->pad(1);
268 os->writeU16(nRectsInUpdate);
269 os->writeBytes(updateOS->data(), updateOS->length());
270 updateOS->clear();
271 }
272
273 updatesSent++;
274 endMsg();
275}
276
277bool SMsgWriterV3::needFakeUpdate()
278{
Pierre Ossman04e62db2009-03-23 16:57:07 +0000279 return wsccb || needSetDesktopSize || needExtendedDesktopSize ||
280 !extendedDesktopSizeMsgs.empty() || needSetDesktopName;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000281}
282
283void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
284{
285 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
286 throw Exception("SMsgWriterV3::startRect: nRects out of sync");
287
288 currentEncoding = encoding;
289 lenBeforeRect = os->length();
290 if (encoding != encodingCopyRect)
291 rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
292
293 os->writeS16(r.tl.x);
294 os->writeS16(r.tl.y);
295 os->writeU16(r.width());
296 os->writeU16(r.height());
297 os->writeU32(encoding);
298}
299
300void SMsgWriterV3::endRect()
301{
302 if (currentEncoding <= encodingMax) {
303 bytesSent[currentEncoding] += os->length() - lenBeforeRect;
304 rectsSent[currentEncoding]++;
305 }
306}