blob: e91e514f4ec3acd7ce0276917a41b9b6b61f391a [file] [log] [blame]
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00001/* Copyright (C) 2002-2004 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),
30 needSetDesktopSize(false)
31{
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
67void SMsgWriterV3::cursorChange(WriteSetCursorCallback* cb)
68{
69 wsccb = cb;
70}
71
72void SMsgWriterV3::writeSetCursor(int width, int height, int hotspotX,
73 int hotspotY, void* data, void* mask)
74{
75 if (!wsccb) return;
76 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
77 throw Exception("SMsgWriterV3::writeSetCursor: nRects out of sync");
78 os->writeS16(hotspotX);
79 os->writeS16(hotspotY);
80 os->writeU16(width);
81 os->writeU16(height);
82 os->writeU32(pseudoEncodingCursor);
83 os->writeBytes(data, width * height * (cp->pf().bpp/8));
84 os->writeBytes(mask, (width+7)/8 * height);
85}
86
Peter Åstrand1e9d32f2005-02-16 13:00:38 +000087void SMsgWriterV3::writeSetXCursor(int width, int height, int hotspotX,
88 int hotspotY, void* data, void* mask)
89{
90 if (!wsccb) return;
91 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
92 throw Exception("SMsgWriterV3::writeSetXCursor: nRects out of sync");
93 os->writeS16(hotspotX);
94 os->writeS16(hotspotY);
95 os->writeU16(width);
96 os->writeU16(height);
97 os->writeU32(pseudoEncodingXCursor);
98 // FIXME: We only support black and white cursors, currently. We
99 // could pass the correct color by using the pix0/pix1 values
100 // returned from getBitmap, in writeSetCursorCallback. However, we
101 // would then need to undo the conversion from rgb to Pixel that is
102 // done by FakeAllocColor.
Constantin Kaplinsky40760022005-09-09 07:19:07 +0000103 if (width * height) {
104 os->writeU8(0);
105 os->writeU8(0);
106 os->writeU8(0);
107 os->writeU8(255);
108 os->writeU8(255);
109 os->writeU8(255);
110 os->writeBytes(data, (width+7)/8 * height);
111 os->writeBytes(mask, (width+7)/8 * height);
112 }
Peter Åstrand1e9d32f2005-02-16 13:00:38 +0000113}
114
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000115void SMsgWriterV3::writeFramebufferUpdateStart(int nRects)
116{
117 startMsg(msgTypeFramebufferUpdate);
118 os->pad(1);
119 if (wsccb) nRects++;
120 if (needSetDesktopSize) nRects++;
121 os->writeU16(nRects);
122 nRectsInUpdate = 0;
123 nRectsInHeader = nRects;
124 if (wsccb) {
125 wsccb->writeSetCursorCallback();
126 wsccb = 0;
127 }
128}
129
130void SMsgWriterV3::writeFramebufferUpdateStart()
131{
132 nRectsInUpdate = nRectsInHeader = 0;
133 if (!updateOS)
134 updateOS = new rdr::MemOutStream;
135 os = updateOS;
136}
137
138void SMsgWriterV3::writeFramebufferUpdateEnd()
139{
140 if (needSetDesktopSize) {
141 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
142 throw Exception("SMsgWriterV3 setDesktopSize: nRects out of sync");
143 os->writeS16(0);
144 os->writeS16(0);
145 os->writeU16(cp->width);
146 os->writeU16(cp->height);
147 os->writeU32(pseudoEncodingDesktopSize);
148 needSetDesktopSize = false;
149 }
150
151 if (nRectsInUpdate != nRectsInHeader && nRectsInHeader)
152 throw Exception("SMsgWriterV3::writeFramebufferUpdateEnd: "
153 "nRects out of sync");
154 if (os == updateOS) {
155 os = realOS;
156 startMsg(msgTypeFramebufferUpdate);
157 os->pad(1);
158 os->writeU16(nRectsInUpdate);
159 os->writeBytes(updateOS->data(), updateOS->length());
160 updateOS->clear();
161 }
162
163 updatesSent++;
164 endMsg();
165}
166
167bool SMsgWriterV3::needFakeUpdate()
168{
169 return wsccb || needSetDesktopSize;
170}
171
172void SMsgWriterV3::startRect(const Rect& r, unsigned int encoding)
173{
174 if (++nRectsInUpdate > nRectsInHeader && nRectsInHeader)
175 throw Exception("SMsgWriterV3::startRect: nRects out of sync");
176
177 currentEncoding = encoding;
178 lenBeforeRect = os->length();
179 if (encoding != encodingCopyRect)
180 rawBytesEquivalent += 12 + r.width() * r.height() * (bpp()/8);
181
182 os->writeS16(r.tl.x);
183 os->writeS16(r.tl.y);
184 os->writeU16(r.width());
185 os->writeU16(r.height());
186 os->writeU32(encoding);
187}
188
189void SMsgWriterV3::endRect()
190{
191 if (currentEncoding <= encodingMax) {
192 bytesSent[currentEncoding] += os->length() - lenBeforeRect;
193 rectsSent[currentEncoding]++;
194 }
195}
196
197void SMsgWriterV3::setOutStream(rdr::OutStream* os_)
198{
199 SMsgWriter::setOutStream(os_);
200 realOS = os;
201}