blob: a9e12d703626251655fd6af2e50af570b5e4d6b2 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
Pierre Ossman0ff26552016-02-05 10:26:56 +01002 * Copyright 2009-2019 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 */
Pierre Ossmana4c0aac2017-02-19 15:50:29 +010019
20#include <assert.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000021#include <stdio.h>
Pierre Ossmana4c0aac2017-02-19 15:50:29 +010022
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000023#include <rdr/InStream.h>
Pierre Ossman0ff26552016-02-05 10:26:56 +010024#include <rdr/ZlibInStream.h>
25
26#include <rfb/msgTypes.h>
27#include <rfb/clipboardTypes.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000028#include <rfb/Exception.h>
Pierre Ossmane9e7da92016-04-20 09:38:06 +020029#include <rfb/LogWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000030#include <rfb/util.h>
31#include <rfb/CMsgHandler.h>
32#include <rfb/CMsgReader.h>
33
Pierre Ossmane9e7da92016-04-20 09:38:06 +020034static rfb::LogWriter vlog("CMsgReader");
35
Pierre Ossman0ff26552016-02-05 10:26:56 +010036static rfb::IntParameter maxCutText("MaxCutText", "Maximum permitted length of an incoming clipboard update", 256*1024);
37
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000038using namespace rfb;
39
40CMsgReader::CMsgReader(CMsgHandler* handler_, rdr::InStream* is_)
41 : imageBufIdealSize(0), handler(handler_), is(is_),
Pierre Ossman7bfb73b2015-11-10 13:03:26 +010042 nUpdateRectsLeft(0)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000043{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000044}
45
46CMsgReader::~CMsgReader()
47{
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000048}
49
Pierre Ossman7638e9c2014-01-16 13:12:40 +010050void CMsgReader::readServerInit()
51{
52 int width = is->readU16();
53 int height = is->readU16();
Pierre Ossman7638e9c2014-01-16 13:12:40 +010054 PixelFormat pf;
55 pf.read(is);
Pierre Ossman7638e9c2014-01-16 13:12:40 +010056 CharArray name(is->readString());
Pierre Ossmandd45b442018-10-31 17:08:59 +010057 handler->serverInit(width, height, pf, name.buf);
Pierre Ossman7638e9c2014-01-16 13:12:40 +010058}
59
60void CMsgReader::readMsg()
61{
62 if (nUpdateRectsLeft == 0) {
63 int type = is->readU8();
64
65 switch (type) {
66 case msgTypeSetColourMapEntries:
67 readSetColourMapEntries();
68 break;
69 case msgTypeBell:
70 readBell();
71 break;
72 case msgTypeServerCutText:
73 readServerCutText();
74 break;
75 case msgTypeFramebufferUpdate:
76 readFramebufferUpdate();
77 break;
78 case msgTypeServerFence:
79 readFence();
80 break;
81 case msgTypeEndOfContinuousUpdates:
82 readEndOfContinuousUpdates();
83 break;
84 default:
Pierre Ossmane9e7da92016-04-20 09:38:06 +020085 vlog.error("unknown message type %d", type);
Pierre Ossman7638e9c2014-01-16 13:12:40 +010086 throw Exception("unknown message type");
87 }
88 } else {
89 int x = is->readU16();
90 int y = is->readU16();
91 int w = is->readU16();
92 int h = is->readU16();
93 int encoding = is->readS32();
94
95 switch (encoding) {
96 case pseudoEncodingLastRect:
97 nUpdateRectsLeft = 1; // this rectangle is the last one
98 break;
Pierre Ossman6b68f972017-02-19 15:51:19 +010099 case pseudoEncodingXCursor:
100 readSetXCursor(w, h, Point(x,y));
101 break;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100102 case pseudoEncodingCursor:
103 readSetCursor(w, h, Point(x,y));
104 break;
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100105 case pseudoEncodingCursorWithAlpha:
106 readSetCursorWithAlpha(w, h, Point(x,y));
107 break;
Pierre Ossman4a6266f2018-11-05 16:28:18 +0100108 case pseudoEncodingVMwareCursor:
109 readSetVMwareCursor(w, h, Point(x,y));
110 break;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100111 case pseudoEncodingDesktopName:
112 readSetDesktopName(x, y, w, h);
113 break;
114 case pseudoEncodingDesktopSize:
115 handler->setDesktopSize(w, h);
116 break;
117 case pseudoEncodingExtendedDesktopSize:
118 readExtendedDesktopSize(x, y, w, h);
119 break;
Pierre Ossman2fa63f82016-12-05 15:26:21 +0100120 case pseudoEncodingLEDState:
121 readLEDState();
Pierre Ossman62b07862018-11-05 16:28:57 +0100122 break;
123 case pseudoEncodingVMwareLEDState:
124 readVMwareLEDState();
125 break;
Pierre Ossman5ae28212017-05-16 14:30:38 +0200126 case pseudoEncodingQEMUKeyEvent:
127 handler->supportsQEMUKeyEvent();
Pierre Ossman2fa63f82016-12-05 15:26:21 +0100128 break;
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100129 default:
130 readRect(Rect(x, y, x+w, y+h), encoding);
131 break;
132 };
133
134 nUpdateRectsLeft--;
135 if (nUpdateRectsLeft == 0)
136 handler->framebufferUpdateEnd();
137 }
138}
139
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000140void CMsgReader::readSetColourMapEntries()
141{
142 is->skip(1);
143 int firstColour = is->readU16();
144 int nColours = is->readU16();
145 rdr::U16Array rgbs(nColours * 3);
146 for (int i = 0; i < nColours * 3; i++)
147 rgbs.buf[i] = is->readU16();
148 handler->setColourMapEntries(firstColour, nColours, rgbs.buf);
149}
150
151void CMsgReader::readBell()
152{
153 handler->bell();
154}
155
156void CMsgReader::readServerCutText()
157{
158 is->skip(3);
Adam Tkacacf6c6b2009-02-13 12:42:05 +0000159 rdr::U32 len = is->readU32();
Pierre Ossman0ff26552016-02-05 10:26:56 +0100160
161 if (len & 0x80000000) {
162 rdr::S32 slen = len;
163 slen = -slen;
164 readExtendedClipboard(slen);
165 return;
166 }
167
168 if (len > (size_t)maxCutText) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000169 is->skip(len);
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200170 vlog.error("cut text too long (%d bytes) - ignoring",len);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000171 return;
172 }
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200173 CharArray ca(len);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000174 is->readBytes(ca.buf, len);
Pierre Ossman546b2ad2019-05-02 12:32:03 +0200175 CharArray filtered(convertLF(ca.buf, len));
Pierre Ossman66f1db52019-05-02 12:32:03 +0200176 handler->serverCutText(filtered.buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000177}
178
Pierre Ossman0ff26552016-02-05 10:26:56 +0100179void CMsgReader::readExtendedClipboard(rdr::S32 len)
180{
181 rdr::U32 flags;
182 rdr::U32 action;
183
184 if (len < 4)
185 throw Exception("Invalid extended clipboard message");
186 if (len > maxCutText) {
187 vlog.error("Extended clipboard message too long (%d bytes) - ignoring", len);
188 is->skip(len);
189 return;
190 }
191
192 flags = is->readU32();
193 action = flags & clipboardActionMask;
194
195 if (action & clipboardCaps) {
196 int i;
197 size_t num;
198 rdr::U32 lengths[16];
199
200 num = 0;
201 for (i = 0;i < 16;i++) {
202 if (flags & (1 << i))
203 num++;
204 }
205
206 if (len < (rdr::S32)(4 + 4*num))
207 throw Exception("Invalid extended clipboard message");
208
209 num = 0;
210 for (i = 0;i < 16;i++) {
211 if (flags & (1 << i))
212 lengths[num++] = is->readU32();
213 }
214
215 handler->handleClipboardCaps(flags, lengths);
216 } else if (action == clipboardProvide) {
217 rdr::ZlibInStream zis;
218
219 int i;
220 size_t num;
221 size_t lengths[16];
222 rdr::U8* buffers[16];
223
224 zis.setUnderlying(is, len - 4);
225
226 num = 0;
227 for (i = 0;i < 16;i++) {
228 if (!(flags & 1 << i))
229 continue;
230
231 lengths[num] = zis.readU32();
232 if (lengths[num] > (size_t)maxCutText) {
233 vlog.error("Extended clipboard data too long (%d bytes) - ignoring",
234 (unsigned)lengths[num]);
235 zis.skip(lengths[num]);
236 flags &= ~(1 << i);
237 continue;
238 }
239
240 buffers[num] = new rdr::U8[lengths[num]];
241 zis.readBytes(buffers[num], lengths[num]);
242 num++;
243 }
244
245 zis.removeUnderlying();
246
247 handler->handleClipboardProvide(flags, lengths, buffers);
248
249 num = 0;
250 for (i = 0;i < 16;i++) {
251 if (!(flags & 1 << i))
252 continue;
253 delete [] buffers[num++];
254 }
255 } else {
256 switch (action) {
257 case clipboardRequest:
258 handler->handleClipboardRequest(flags);
259 break;
260 case clipboardPeek:
261 handler->handleClipboardPeek(flags);
262 break;
263 case clipboardNotify:
264 handler->handleClipboardNotify(flags);
265 break;
266 default:
267 throw Exception("Invalid extended clipboard action");
268 }
269 }
270}
271
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100272void CMsgReader::readFence()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000273{
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100274 rdr::U32 flags;
275 rdr::U8 len;
276 char data[64];
277
278 is->skip(3);
279
280 flags = is->readU32();
281
282 len = is->readU8();
283 if (len > sizeof(data)) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200284 vlog.error("Ignoring fence with too large payload");
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100285 is->skip(len);
286 return;
287 }
288
289 is->readBytes(data, len);
290
291 handler->fence(flags, len, data);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000292}
293
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100294void CMsgReader::readEndOfContinuousUpdates()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000295{
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100296 handler->endOfContinuousUpdates();
297}
298
299void CMsgReader::readFramebufferUpdate()
300{
301 is->skip(1);
302 nUpdateRectsLeft = is->readU16();
303 handler->framebufferUpdateStart();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000304}
305
Peter Ã…strand98fe98c2010-02-10 07:43:02 +0000306void CMsgReader::readRect(const Rect& r, int encoding)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000307{
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200308 if ((r.br.x > handler->server.width()) ||
309 (r.br.y > handler->server.height())) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200310 vlog.error("Rect too big: %dx%d at %d,%d exceeds %dx%d",
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000311 r.width(), r.height(), r.tl.x, r.tl.y,
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200312 handler->server.width(), handler->server.height());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000313 throw Exception("Rect too big");
314 }
315
316 if (r.is_empty())
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200317 vlog.error("zero size rect");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000318
Pierre Ossmanfdba3fe2014-01-31 13:12:18 +0100319 handler->dataRect(r, encoding);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000320}
321
Pierre Ossman6b68f972017-02-19 15:51:19 +0100322void CMsgReader::readSetXCursor(int width, int height, const Point& hotspot)
323{
Michal Srbc26b4b32017-04-06 23:52:22 +0300324 if (width > maxCursorSize || height > maxCursorSize)
325 throw Exception("Too big cursor");
326
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100327 rdr::U8Array rgba(width*height*4);
Pierre Ossman6b68f972017-02-19 15:51:19 +0100328
Brian P. Hinz33d78322017-11-16 17:46:15 -0500329 if (width * height > 0) {
Pierre Ossman9c88e0d2018-09-13 12:30:30 +0200330 rdr::U8 pr, pg, pb;
331 rdr::U8 sr, sg, sb;
332 int data_len = ((width+7)/8) * height;
333 int mask_len = ((width+7)/8) * height;
334 rdr::U8Array data(data_len);
335 rdr::U8Array mask(mask_len);
336
337 int x, y;
338 rdr::U8* out;
339
Pierre Ossman6b68f972017-02-19 15:51:19 +0100340 pr = is->readU8();
341 pg = is->readU8();
342 pb = is->readU8();
343
344 sr = is->readU8();
345 sg = is->readU8();
346 sb = is->readU8();
347
348 is->readBytes(data.buf, data_len);
349 is->readBytes(mask.buf, mask_len);
Pierre Ossman6b68f972017-02-19 15:51:19 +0100350
Pierre Ossman9c88e0d2018-09-13 12:30:30 +0200351 int maskBytesPerRow = (width+7)/8;
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100352 out = rgba.buf;
Pierre Ossman9c88e0d2018-09-13 12:30:30 +0200353 for (y = 0;y < height;y++) {
354 for (x = 0;x < width;x++) {
355 int byte = y * maskBytesPerRow + x / 8;
356 int bit = 7 - x % 8;
Pierre Ossman6b68f972017-02-19 15:51:19 +0100357
Pierre Ossman9c88e0d2018-09-13 12:30:30 +0200358 if (data.buf[byte] & (1 << bit)) {
359 out[0] = pr;
360 out[1] = pg;
361 out[2] = pb;
362 } else {
363 out[0] = sr;
364 out[1] = sg;
365 out[2] = sb;
366 }
367
368 if (mask.buf[byte] & (1 << bit))
369 out[3] = 255;
370 else
371 out[3] = 0;
372
373 out += 4;
Pierre Ossman6b68f972017-02-19 15:51:19 +0100374 }
Pierre Ossman6b68f972017-02-19 15:51:19 +0100375 }
376 }
377
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100378 handler->setCursor(width, height, hotspot, rgba.buf);
Pierre Ossman6b68f972017-02-19 15:51:19 +0100379}
380
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000381void CMsgReader::readSetCursor(int width, int height, const Point& hotspot)
382{
Michal Srbc26b4b32017-04-06 23:52:22 +0300383 if (width > maxCursorSize || height > maxCursorSize)
384 throw Exception("Too big cursor");
385
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200386 int data_len = width * height * (handler->server.pf().bpp/8);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000387 int mask_len = ((width+7)/8) * height;
388 rdr::U8Array data(data_len);
389 rdr::U8Array mask(mask_len);
390
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100391 int x, y;
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100392 rdr::U8Array rgba(width*height*4);
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100393 rdr::U8* in;
394 rdr::U8* out;
395
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000396 is->readBytes(data.buf, data_len);
397 is->readBytes(mask.buf, mask_len);
398
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100399 int maskBytesPerRow = (width+7)/8;
400 in = data.buf;
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100401 out = rgba.buf;
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100402 for (y = 0;y < height;y++) {
403 for (x = 0;x < width;x++) {
404 int byte = y * maskBytesPerRow + x / 8;
405 int bit = 7 - x % 8;
406
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200407 handler->server.pf().rgbFromBuffer(out, in, 1);
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100408
409 if (mask.buf[byte] & (1 << bit))
410 out[3] = 255;
411 else
412 out[3] = 0;
413
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200414 in += handler->server.pf().bpp/8;
Pierre Ossman6a1a0d02017-02-19 15:48:17 +0100415 out += 4;
416 }
417 }
418
Pierre Ossmanbeb59a42018-11-07 21:36:05 +0100419 handler->setCursor(width, height, hotspot, rgba.buf);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000420}
421
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100422void CMsgReader::readSetCursorWithAlpha(int width, int height, const Point& hotspot)
423{
Michal Srbc26b4b32017-04-06 23:52:22 +0300424 if (width > maxCursorSize || height > maxCursorSize)
425 throw Exception("Too big cursor");
426
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100427 int encoding;
428
429 const PixelFormat rgbaPF(32, 32, false, true, 255, 255, 255, 16, 8, 0);
430 ManagedPixelBuffer pb(rgbaPF, width, height);
431 PixelFormat origPF;
432
433 rdr::U8* buf;
434 int stride;
435
436 encoding = is->readS32();
437
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200438 origPF = handler->server.pf();
439 handler->server.setPF(rgbaPF);
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100440 handler->readAndDecodeRect(pb.getRect(), encoding, &pb);
Pierre Ossmanb14a6bc2018-06-18 15:44:26 +0200441 handler->server.setPF(origPF);
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100442
443 // On-wire data has pre-multiplied alpha, but we store it
444 // non-pre-multiplied
445 buf = pb.getBufferRW(pb.getRect(), &stride);
446 assert(stride == width);
447
448 for (int i = 0;i < pb.area();i++) {
449 rdr::U8 alpha;
450
451 alpha = buf[3];
452 if (alpha == 0)
453 alpha = 1; // Avoid division by zero
454
455 buf[0] = (unsigned)buf[0] * 255/alpha;
456 buf[1] = (unsigned)buf[1] * 255/alpha;
457 buf[2] = (unsigned)buf[2] * 255/alpha;
Pierre Ossmana4c0aac2017-02-19 15:50:29 +0100458
459 buf += 4;
460 }
461
462 pb.commitBufferRW(pb.getRect());
463
464 handler->setCursor(width, height, hotspot,
465 pb.getBuffer(pb.getRect(), &stride));
466}
467
Pierre Ossman4a6266f2018-11-05 16:28:18 +0100468void CMsgReader::readSetVMwareCursor(int width, int height, const Point& hotspot)
469{
470 if (width > maxCursorSize || height > maxCursorSize)
471 throw Exception("Too big cursor");
472
473 rdr::U8 type;
474
475 type = is->readU8();
476 is->skip(1);
477
478 if (type == 0) {
479 int len = width * height * (handler->server.pf().bpp/8);
480 rdr::U8Array andMask(len);
481 rdr::U8Array xorMask(len);
482
483 rdr::U8Array data(width*height*4);
484
485 rdr::U8* andIn;
486 rdr::U8* xorIn;
487 rdr::U8* out;
488 int Bpp;
489
490 is->readBytes(andMask.buf, len);
491 is->readBytes(xorMask.buf, len);
492
493 andIn = andMask.buf;
494 xorIn = xorMask.buf;
495 out = data.buf;
496 Bpp = handler->server.pf().bpp/8;
497 for (int y = 0;y < height;y++) {
498 for (int x = 0;x < width;x++) {
499 Pixel andPixel, xorPixel;
500
501 andPixel = handler->server.pf().pixelFromBuffer(andIn);
502 xorPixel = handler->server.pf().pixelFromBuffer(xorIn);
503 andIn += Bpp;
504 xorIn += Bpp;
505
506 if (andPixel == 0) {
507 rdr::U8 r, g, b;
508
509 // Opaque pixel
510
511 handler->server.pf().rgbFromPixel(xorPixel, &r, &g, &b);
512 *out++ = r;
513 *out++ = g;
514 *out++ = b;
515 *out++ = 0xff;
516 } else if (xorPixel == 0) {
517 // Fully transparent pixel
518 *out++ = 0;
519 *out++ = 0;
520 *out++ = 0;
521 *out++ = 0;
522 } else if (andPixel == xorPixel) {
523 // Inverted pixel
524
525 // We don't really support this, so just turn the pixel black
526 // FIXME: Do an outline like WinVNC does?
527 *out++ = 0;
528 *out++ = 0;
529 *out++ = 0;
530 *out++ = 0xff;
531 } else {
532 // Partially transparent/inverted pixel
533
534 // We _really_ can't handle this, just make it black
535 *out++ = 0;
536 *out++ = 0;
537 *out++ = 0;
538 *out++ = 0xff;
539 }
540 }
541 }
542
543 handler->setCursor(width, height, hotspot, data.buf);
544 } else if (type == 1) {
545 rdr::U8Array data(width*height*4);
546
547 // FIXME: Is alpha premultiplied?
548 is->readBytes(data.buf, width*height*4);
549
550 handler->setCursor(width, height, hotspot, data.buf);
551 } else {
552 throw Exception("Unknown cursor type");
553 }
554}
555
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100556void CMsgReader::readSetDesktopName(int x, int y, int w, int h)
557{
558 char* name = is->readString();
559
560 if (x || y || w || h) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +0200561 vlog.error("Ignoring DesktopName rect with non-zero position/size");
Pierre Ossman7638e9c2014-01-16 13:12:40 +0100562 } else {
563 handler->setName(name);
564 }
565
566 delete [] name;
567}
568
569void CMsgReader::readExtendedDesktopSize(int x, int y, int w, int h)
570{
571 unsigned int screens, i;
572 rdr::U32 id, flags;
573 int sx, sy, sw, sh;
574 ScreenSet layout;
575
576 screens = is->readU8();
577 is->skip(3);
578
579 for (i = 0;i < screens;i++) {
580 id = is->readU32();
581 sx = is->readU16();
582 sy = is->readU16();
583 sw = is->readU16();
584 sh = is->readU16();
585 flags = is->readU32();
586
587 layout.add_screen(Screen(id, sx, sy, sw, sh, flags));
588 }
589
590 handler->setExtendedDesktopSize(x, y, w, h, layout);
591}
Pierre Ossman2fa63f82016-12-05 15:26:21 +0100592
593void CMsgReader::readLEDState()
594{
595 rdr::U8 state;
596
597 state = is->readU8();
598
599 handler->setLEDState(state);
600}
Pierre Ossman62b07862018-11-05 16:28:57 +0100601
602void CMsgReader::readVMwareLEDState()
603{
604 rdr::U32 state;
605
606 state = is->readU32();
607
608 // As luck has it, this extension uses the same bit definitions,
609 // so no conversion required
610
611 handler->setLEDState(state);
612}