1 /*
2  * Copyright (c) 2020 Andri Yngvason
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <assert.h>
20 #include <string.h>
21 #include <stdbool.h>
22 #include <pixman.h>
23 #include <rfb/rfbclient.h>
24 #include <wayland-client.h>
25 
26 #include "vnc.h"
27 
28 extern const unsigned short code_map_linux_to_qnum[];
29 extern const unsigned int code_map_linux_to_qnum_len;
30 
vnc_client_alloc_fb(rfbClient * client)31 static rfbBool vnc_client_alloc_fb(rfbClient* client)
32 {
33 	struct vnc_client* self = rfbClientGetClientData(client, NULL);
34 	assert(self);
35 
36 	return self->alloc_fb(self) < 0 ? FALSE : TRUE;
37 }
38 
vnc_client_update_box(rfbClient * client,int x,int y,int width,int height)39 static void vnc_client_update_box(rfbClient* client, int x, int y, int width,
40 		int height)
41 {
42 	struct vnc_client* self = rfbClientGetClientData(client, NULL);
43 	assert(self);
44 
45 	pixman_region_union_rect(&self->damage, &self->damage, x, y, width,
46 			height);
47 }
48 
vnc_client_finish_update(rfbClient * client)49 static void vnc_client_finish_update(rfbClient* client)
50 {
51 	struct vnc_client* self = rfbClientGetClientData(client, NULL);
52 	assert(self);
53 
54 	self->update_fb(self);
55 
56 	pixman_region_clear(&self->damage);
57 }
58 
vnc_client_got_cut_text(rfbClient * client,const char * text,int len)59 static void vnc_client_got_cut_text(rfbClient* client, const char* text,
60 		int len)
61 {
62 	struct vnc_client* self = rfbClientGetClientData(client, NULL);
63 	assert(self);
64 
65 	if (self->cut_text)
66 		self->cut_text(self, text, len);
67 }
68 
vnc_client_create(void)69 struct vnc_client* vnc_client_create(void)
70 {
71 	struct vnc_client* self = calloc(1, sizeof(*self));
72 	if (!self)
73 		return NULL;
74 
75 	/* These are defaults that can be changed with
76 	 * vnc_client_set_pixel_format().
77 	 */
78 	int bits_per_sample = 8;
79 	int samples_per_pixel = 3;
80 	int bytes_per_pixel = 4;
81 
82 	rfbClient* client = rfbGetClient(bits_per_sample, samples_per_pixel,
83 			bytes_per_pixel);
84 	if (!client)
85 		goto failure;
86 
87 	self->client = client;
88 	rfbClientSetClientData(client, NULL, self);
89 
90 	client->MallocFrameBuffer = vnc_client_alloc_fb;
91 	client->GotFrameBufferUpdate = vnc_client_update_box;
92 	client->FinishedFrameBufferUpdate = vnc_client_finish_update;
93 	client->GotXCutText = vnc_client_got_cut_text;
94 
95 	return self;
96 
97 failure:
98 	free(self);
99 	return NULL;
100 }
101 
vnc_client_destroy(struct vnc_client * self)102 void vnc_client_destroy(struct vnc_client* self)
103 {
104 	rfbClientCleanup(self->client);
105 	free(self);
106 }
107 
vnc_client_connect(struct vnc_client * self,const char * address,int port)108 int vnc_client_connect(struct vnc_client* self, const char* address, int port)
109 {
110 	rfbClient* client = self->client;
111 
112 	if (!ConnectToRFBServer(client, address, port))
113 		return -1;
114 
115 	if (!InitialiseRFBConnection(client))
116 		return -1;
117 
118 	client->width = client->si.framebufferWidth;
119 	client->height = client->si.framebufferHeight;
120 
121 	if (!client->MallocFrameBuffer(client))
122 		return -1;
123 
124 	if (!SetFormatAndEncodings(client))
125 		return -1;
126 
127 	if (client->updateRect.x < 0) {
128 		client->updateRect.x = client->updateRect.y = 0;
129 		client->updateRect.w = client->width;
130 		client->updateRect.h = client->height;
131 	}
132 
133 	if (!SendFramebufferUpdateRequest(client,
134 				client->updateRect.x, client->updateRect.y,
135 				client->updateRect.w, client->updateRect.h,
136 				FALSE))
137 		return -1;
138 
139 	return 0;
140 }
141 
vnc_client_set_pixel_format(struct vnc_client * self,enum wl_shm_format format)142 int vnc_client_set_pixel_format(struct vnc_client* self,
143 		enum wl_shm_format format)
144 {
145 	rfbPixelFormat* dst = &self->client->format;
146 	int bpp = -1;
147 
148 	switch (format) {
149 	case WL_SHM_FORMAT_ARGB8888:
150 	case WL_SHM_FORMAT_XRGB8888:
151 		dst->redShift = 16;
152 		dst->greenShift = 8;
153 		dst->blueShift = 0;
154 		bpp = 32;
155 		break;
156 	default:
157 		return -1;
158 	}
159 
160 	switch (bpp) {
161 	case 32:
162 		dst->bitsPerPixel = 32;
163 		dst->depth = 24;
164 		dst->redMax = 0xff;
165 		dst->greenMax = 0xff;
166 		dst->blueMax = 0xff;
167 		break;
168 	default:
169 		abort();
170 	}
171 
172 	dst->trueColour = 1;
173 	dst->bigEndian = FALSE;
174 	self->client->appData.requestedDepth = dst->depth;
175 
176 	return 0;
177 }
178 
vnc_client_get_width(const struct vnc_client * self)179 int vnc_client_get_width(const struct vnc_client* self)
180 {
181 	return self->client->width;
182 }
183 
vnc_client_get_height(const struct vnc_client * self)184 int vnc_client_get_height(const struct vnc_client* self)
185 {
186 	return self->client->height;
187 }
188 
vnc_client_get_stride(const struct vnc_client * self)189 int vnc_client_get_stride(const struct vnc_client* self)
190 {
191 	// TODO: What happens if bitsPerPixel == 24?
192 	return self->client->width * self->client->format.bitsPerPixel / 8;
193 }
194 
vnc_client_get_fb(const struct vnc_client * self)195 void* vnc_client_get_fb(const struct vnc_client* self)
196 {
197 	return self->client->frameBuffer;
198 }
199 
vnc_client_set_fb(struct vnc_client * self,void * fb)200 void vnc_client_set_fb(struct vnc_client* self, void* fb)
201 {
202 	self->client->frameBuffer = fb;
203 }
204 
vnc_client_get_fd(const struct vnc_client * self)205 int vnc_client_get_fd(const struct vnc_client* self)
206 {
207 	return self->client->sock;
208 }
209 
vnc_client_get_desktop_name(const struct vnc_client * self)210 const char* vnc_client_get_desktop_name(const struct vnc_client* self)
211 {
212 	return self->client->desktopName;
213 }
214 
vnc_client_process(struct vnc_client * self)215 int vnc_client_process(struct vnc_client* self)
216 {
217 	return HandleRFBServerMessage(self->client) ? 0 : -1;
218 }
219 
vnc_client_send_pointer_event(struct vnc_client * self,int x,int y,uint32_t button_mask)220 void vnc_client_send_pointer_event(struct vnc_client* self, int x, int y,
221 		uint32_t button_mask)
222 {
223 	SendPointerEvent(self->client, x, y, button_mask);
224 }
225 
vnc_client_send_keyboard_event(struct vnc_client * self,uint32_t symbol,uint32_t code,bool is_pressed)226 void vnc_client_send_keyboard_event(struct vnc_client* self, uint32_t symbol,
227 		uint32_t code, bool is_pressed)
228 {
229 	if (code >= code_map_linux_to_qnum_len)
230 		return;
231 
232 	uint32_t qnum = code_map_linux_to_qnum[code];
233 	if (!qnum)
234 		qnum = code;
235 
236 	if (!SendExtendedKeyEvent(self->client, symbol, qnum, is_pressed))
237 		SendKeyEvent(self->client, symbol, is_pressed);
238 }
239 
vnc_client_set_encodings(struct vnc_client * self,const char * encodings)240 void vnc_client_set_encodings(struct vnc_client* self, const char* encodings)
241 {
242 	self->client->appData.encodingsString = encodings;
243 }
244 
vnc_client_set_quality_level(struct vnc_client * self,int value)245 void vnc_client_set_quality_level(struct vnc_client* self, int value)
246 {
247 	self->client->appData.qualityLevel = value;
248 }
249 
vnc_client_set_compression_level(struct vnc_client * self,int value)250 void vnc_client_set_compression_level(struct vnc_client* self, int value)
251 {
252 	self->client->appData.compressLevel = value;
253 }
254 
vnc_client_send_cut_text(struct vnc_client * self,const char * text,size_t len)255 void vnc_client_send_cut_text(struct vnc_client* self, const char* text,
256 		size_t len)
257 {
258 	// libvncclient doesn't modify text, so typecast is OK.
259 	SendClientCutText(self->client, (char*)text, len);
260 }
261