blob: 1271619505e1058b9652ba5731d25a6e99d3f452 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18#include <rdr/OutStream.h>
19#include <rdr/MemOutStream.h>
20#include <rfb/msgTypes.h>
21#include <rfb/Exception.h>
22#include <rfb/ConnParams.h>
23#include <rfb/SMsgWriterV3.h>
24
25using namespace rfb;
26
27SMsgWriterV3::SMsgWriterV3(ConnParams* cp, rdr::OutStream* os)
28 : SMsgWriter(cp, os), updateOS(0), realOS(os), nRectsInUpdate(0),
29 nRectsInHeader(0), wsccb(0),
Peter Åstrandc39e0782009-01-15 12:21:42 +000030 needSetDesktopSize(false), needSetDesktopName(false)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000031{
32}
33
34SMsgWriterV3::~SMsgWriterV3()
35{
36 delete updateOS;
37}
38
39void SMsgWriterV3::writeServerInit()
40{
41 os->writeU16(cp->width);
42 os->writeU16(cp->height);
43 cp->pf().write(os);
44 os->writeString(cp->name());
45 endMsg();
46}
47
48void SMsgWriterV3::startMsg(int type)
49{
50 if (os != realOS)
51 throw Exception("startMsg called while writing an update?");
52
53 os->writeU8(type);
54}
55
56void SMsgWriterV3::endMsg()
57{
58 os->flush();
59}
60
61bool SMsgWriterV3::writeSetDesktopSize() {
62 if (!cp->supportsDesktopResize) return false;
63 needSetDesktopSize = true;
64 return true;
65}
66
Peter Åstrandc39e0782009-01-15 12:21:42 +000067bool SMsgWriterV3::writeSetDesktopName() {
68 if (!cp->supportsDesktopRename) return false;
69 needSetDesktopName = true;
70 return true;
71}
72
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000073void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
74{
75 wsccb = cb;
76}
77
78void SMsgWriterV3::writeSetCursor(int width, int height, const Point& hotspot,
79 void* data, void* mask)
80{
81 if (!wsccb) return;
82 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
83 throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
84 os->writeS16(hotspot.x);
85 os->writeS16(hotspot.y);
86 os->writeU16(width);
87 os->writeU16(height);
88 os->writeU32(pseudoEncodingCursor);
89 os->writeBytes(data, width * height * (cp->pf().bpp/8));
90 os->writeBytes(mask, (width+7)/8 * height);
91}
92
93void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
94 int hotspotY, void* data, void* mask)
95{
96 if (!wsccb) return;
97 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
98 throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
99 os->writeS16(hotspotX);
100 os->writeS16(hotspotY);
101 os->writeU16(width);
102 os->writeU16(height);
103 os->writeU32(pseudoEncodingXCursor);
104 // FIXME: We only support black and white cursors, currently. We
105 // could pass the correct color by using the pix0/pix1 values
106 // returned from getBitmap, in writeSetCursorCallback. However, we
107 // would then need to undo the conversion from rgb to Pixel that is
108 // done by FakeAllocColor.
109 if (width * height) {
110 os->writeU8(0);
111 os->writeU8(0);
112 os->writeU8(0);
113 os->writeU8(255);
114 os->writeU8(255);
115 os->writeU8(255);
116 os->writeBytes(data, (width+7)/8 * height);
117 os->writeBytes(mask, (width+7)/8 * height);
118 }
119}
120
121void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
122{
123 startMsg(msgTypeFramebufferUpdate);
124 os->pad(1);
125 if (wsccb) nRects++;
126 if (needSetDesktopSize) nRects++;
Peter Åstrandc39e0782009-01-15 12:21:42 +0000127 if (needSetDesktopName) nRects++;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000128 os->writeU16(nRects);
129 nRectsInUpdate = 0;
130 nRectsInHeader = nRects;
131 if (wsccb) {
132 wsccb->writeSetCursorCallback();
133 wsccb = 0;
134 }
135}
136
137void SMsgWriterV3::writeFramebufferUpdateStart()
138{
139 nRectsInUpdate = nRectsInHeader = 0;
140 if (!updateOS)
141 updateOS = new rdr::MemOutStream;
142 os = updateOS;
143}
144
145void SMsgWriterV3::writeFramebufferUpdateEnd()
146{
147 if (needSetDesktopSize) {
148 if (!cp->supportsDesktopResize)
149 throw Exception("Client does not support desktop resize");
150 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
151 throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
152 os->writeS16(0);
153 os->writeS16(0);
154 os->writeU16(cp->width);
155 os->writeU16(cp->height);
156 os->writeU32(pseudoEncodingDesktopSize);
157 needSetDesktopSize = false;
158 }
159
Peter Åstrandc39e0782009-01-15 12:21:42 +0000160 if (needSetDesktopName) {
161 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
162 throw Exception("SMsgWriterV3 setDesktopName: nRects out of sync");
163 os->writeS16(0);
164 os->writeS16(0);
165 os->writeU16(0);
166 os->writeU16(0);
167 os->writeU32(pseudoEncodingDesktopName);
168 os->writeString(cp->name());
169 needSetDesktopName = false;
170 }
171
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000172 if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
173 throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
174 "nRects out of sync");
175 if (os == updateOS) {
176 os = realOS;
177 startMsg(msgTypeFramebufferUpdate);
178 os->pad(1);
179 os->writeU16(nRectsInUpdate);
180 os->writeBytes(updateOS->data(), updateOS->length());
181 updateOS->clear();
182 }
183
184 updatesSent++;
185 endMsg();
186}
187
188bool SMsgWriterV3::needFakeUpdate()
189{
Peter Åstrandc39e0782009-01-15 12:21:42 +0000190 return wsccb || needSetDesktopSize || needSetDesktopName;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000191}
192
193void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
194{
195 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
196 throw Exception("SMsgWriterV3::startRect: nRects out of sync");
197
198 currentEncoding = encoding;
199 lenBeforeRect = os->length();
200 if (encoding != encodingCopyRect)
201 rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
202
203 os->writeS16(r.tl.x);
204 os->writeS16(r.tl.y);
205 os->writeU16(r.width());
206 os->writeU16(r.height());
207 os->writeU32(encoding);
208}
209
210void SMsgWriterV3::endRect()
211{
212 if (currentEncoding <= encodingMax) {
213 bytesSent[currentEncoding] += os->length() - lenBeforeRect;
214 rectsSent[currentEncoding]++;
215 }
216}