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