blob: f1fa58dd9159733e35ee1b1c22726ae46b2c3cf4 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman7638e9c2014-01-16 13:12:40 +01002 * Copyright 2009-2014 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 <stdio.h>
20#include <rdr/OutStream.h>
21#include <rfb/msgTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010022#include <rfb/fenceTypes.h>
Pierre Ossman5ae28212017-05-16 14:30:38 +020023#include <rfb/qemuTypes.h>
Pierre Ossman7638e9c2014-01-16 13:12:40 +010024#include <rfb/Exception.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000025#include <rfb/PixelFormat.h>
26#include <rfb/Rect.h>
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +020027#include <rfb/ServerParams.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000028#include <rfb/CMsgWriter.h>
29
30using namespace rfb;
31
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +020032CMsgWriter::CMsgWriter(ServerParams* server_, rdr::OutStream* os_)
33 : server(server_), os(os_)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000034{
35}
36
37CMsgWriter::~CMsgWriter()
38{
39}
40
Pierre Ossman7638e9c2014-01-16 13:12:40 +010041void CMsgWriter::writeClientInit(bool shared)
42{
43 os->writeU8(shared);
44 endMsg();
45}
46
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000047void CMsgWriter::writeSetPixelFormat(const PixelFormat& pf)
48{
49 startMsg(msgTypeSetPixelFormat);
50 os->pad(3);
51 pf.write(os);
52 endMsg();
53}
54
Pierre Ossman1143ee62018-06-20 11:40:37 +020055void CMsgWriter::writeSetEncodings(const std::list<rdr::U32> encodings)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000056{
Pierre Ossman1143ee62018-06-20 11:40:37 +020057 std::list<rdr::U32>::const_iterator iter;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058 startMsg(msgTypeSetEncodings);
59 os->skip(1);
Pierre Ossman1143ee62018-06-20 11:40:37 +020060 os->writeU16(encodings.size());
61 for (iter = encodings.begin(); iter != encodings.end(); ++iter)
62 os->writeU32(*iter);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000063 endMsg();
64}
65
Pierre Ossman7638e9c2014-01-16 13:12:40 +010066void CMsgWriter::writeSetDesktopSize(int width, int height,
67 const ScreenSet& layout)
68{
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +020069 if (!server->supportsSetDesktopSize)
Pierre Ossman7638e9c2014-01-16 13:12:40 +010070 throw Exception("Server does not support SetDesktopSize");
71
72 startMsg(msgTypeSetDesktopSize);
73 os->pad(1);
74
75 os->writeU16(width);
76 os->writeU16(height);
77
78 os->writeU8(layout.num_screens());
79 os->pad(1);
80
81 ScreenSet::const_iterator iter;
82 for (iter = layout.begin();iter != layout.end();++iter) {
83 os->writeU32(iter->id);
84 os->writeU16(iter->dimensions.tl.x);
85 os->writeU16(iter->dimensions.tl.y);
86 os->writeU16(iter->dimensions.width());
87 os->writeU16(iter->dimensions.height());
88 os->writeU32(iter->flags);
89 }
90
91 endMsg();
92}
93
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000094void CMsgWriter::writeFramebufferUpdateRequest(const Rect& r, bool incremental)
95{
96 startMsg(msgTypeFramebufferUpdateRequest);
97 os->writeU8(incremental);
98 os->writeU16(r.tl.x);
99 os->writeU16(r.tl.y);
100 os->writeU16(r.width());
101 os->writeU16(r.height());
102 endMsg();
103}
104
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100105void CMsgWriter::writeEnableContinuousUpdates(bool enable,
106 int x, int y, int w, int h)
107{
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200108 if (!server->supportsContinuousUpdates)
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100109 throw Exception("Server does not support continuous updates");
110
111 startMsg(msgTypeEnableContinuousUpdates);
112
113 os->writeU8(!!enable);
114
115 os->writeU16(x);
116 os->writeU16(y);
117 os->writeU16(w);
118 os->writeU16(h);
119
120 endMsg();
121}
122
123void CMsgWriter::writeFence(rdr::U32 flags, unsigned len, const char data[])
124{
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200125 if (!server->supportsFence)
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100126 throw Exception("Server does not support fences");
127 if (len > 64)
128 throw Exception("Too large fence payload");
129 if ((flags & ~fenceFlagsSupported) != 0)
130 throw Exception("Unknown fence flags");
131
132 startMsg(msgTypeClientFence);
133 os->pad(3);
134
135 os->writeU32(flags);
136
137 os->writeU8(len);
138 os->writeBytes(data, len);
139
140 endMsg();
141}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000142
Pierre Ossman59da99f2016-02-05 10:43:12 +0100143void CMsgWriter::writeKeyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000144{
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200145 if (!server->supportsQEMUKeyEvent || !keycode) {
Pierre Ossman5ae28212017-05-16 14:30:38 +0200146 /* This event isn't meaningful without a valid keysym */
147 if (!keysym)
148 return;
149
150 startMsg(msgTypeKeyEvent);
151 os->writeU8(down);
152 os->pad(2);
153 os->writeU32(keysym);
154 endMsg();
155 } else {
156 startMsg(msgTypeQEMUClientMessage);
157 os->writeU8(qemuExtendedKeyEvent);
158 os->writeU16(down);
159 os->writeU32(keysym);
160 os->writeU32(keycode);
161 endMsg();
162 }
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000163}
164
165
Pierre Ossman59da99f2016-02-05 10:43:12 +0100166void CMsgWriter::writePointerEvent(const Point& pos, int buttonMask)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000167{
168 Point p(pos);
169 if (p.x < 0) p.x = 0;
170 if (p.y < 0) p.y = 0;
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200171 if (p.x >= server->width()) p.x = server->width() - 1;
172 if (p.y >= server->height()) p.y = server->height() - 1;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000173
174 startMsg(msgTypePointerEvent);
175 os->writeU8(buttonMask);
176 os->writeU16(p.x);
177 os->writeU16(p.y);
178 endMsg();
179}
180
181
Pierre Ossman66f1db52019-05-02 12:32:03 +0200182void CMsgWriter::writeClientCutText(const char* str)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000183{
Pierre Ossman66f1db52019-05-02 12:32:03 +0200184 size_t len;
185
186 if (strchr(str, '\r') != NULL)
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200187 throw Exception("Invalid carriage return in clipboard data");
188
Pierre Ossman66f1db52019-05-02 12:32:03 +0200189 len = strlen(str);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000190 startMsg(msgTypeClientCutText);
191 os->pad(3);
192 os->writeU32(len);
193 os->writeBytes(str, len);
194 endMsg();
195}
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100196
197void CMsgWriter::startMsg(int type)
198{
199 os->writeU8(type);
200}
201
202void CMsgWriter::endMsg()
203{
204 os->flush();
205}