wok view fbvnc/stuff/fbvnc.u @ rev 19660
Up cookutils (874)
author | Aleksej Bobylev <al.bobylev@gmail.com> |
---|---|
date | Sat Jan 28 13:03:20 2017 +0200 (2017-01-28) |
parents | |
children |
line source
1 --- draw.h
2 +++ draw.h
3 @@ -15,5 +15,11 @@
4 void fb_cmap(void);
6 /* helper functions */
7 +struct rgb_conv {
8 + int rshl, gshl;
9 + int rskp, gskp, bskp;
10 + int rmax, gmax, bmax;
11 +};
12 +void fill_rgb_conv(int mode, struct rgb_conv *s);
13 void fb_set(int r, int c, void *mem, int len);
14 unsigned fb_val(int r, int g, int b);
15 --- draw.c
16 +++ draw.c
17 @@ -10,14 +10,13 @@
19 #define MIN(a, b) ((a) < (b) ? (a) : (b))
20 #define MAX(a, b) ((a) > (b) ? (a) : (b))
21 -#define NLEVELS (1 << 8)
22 +#define NLEVELS (1 << 16)
24 static int fd;
25 static void *fb;
26 static struct fb_var_screeninfo vinfo;
27 static struct fb_fix_screeninfo finfo;
28 -static int bpp;
29 -static int nr, ng, nb;
30 +static int bytes_per_pixel;
32 static int fb_len(void)
33 {
34 @@ -28,10 +27,12 @@
35 {
36 static unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
37 struct fb_cmap cmap;
38 +
39 if (finfo.visual == FB_VISUAL_TRUECOLOR)
40 return;
41 +
42 cmap.start = 0;
43 - cmap.len = MAX(nr, MAX(ng, nb));
44 + cmap.len = NLEVELS;
45 cmap.red = red;
46 cmap.green = green;
47 cmap.blue = blue;
48 @@ -41,24 +42,39 @@
50 void fb_cmap(void)
51 {
52 - unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
53 + struct fb_bitfield *color[3] = {
54 + &vinfo.blue, &vinfo.green, &vinfo.red
55 + };
56 + int eye_sensibility[3] = { 2, 0, 1 }; // higher=red, blue, lower=green
57 struct fb_cmap cmap;
58 - int i;
59 + unsigned short map[3][NLEVELS];
60 + int i, j, n, offset;
61 +
62 if (finfo.visual == FB_VISUAL_TRUECOLOR)
63 return;
65 - for (i = 0; i < nr; i++)
66 - red[i] = (65535 / (nr - 1)) * i;
67 - for (i = 0; i < ng; i++)
68 - green[i] = (65535 / (ng - 1)) * i;
69 - for (i = 0; i < nb; i++)
70 - blue[i] = (65535 / (nb - 1)) * i;
71 -
72 + for (i = 0, n = vinfo.bits_per_pixel; i < 3; i++) {
73 + n -= color[eye_sensibility[i]]->length = n / (3 - i);
74 + }
75 + n = (1 << vinfo.bits_per_pixel);
76 + if (n > NLEVELS)
77 + n = NLEVELS;
78 + for (i = offset = 0; i < 3; i++) {
79 + int length = color[i]->length;
80 + color[i]->offset = offset;
81 + for (j = 0; j < n; j++) {
82 + int k = (j >> offset) << (16 - length);
83 + if (k == (0xFFFF << (16 - length)))
84 + k = 0xFFFF;
85 + map[i][j] = k;
86 + }
87 + offset += length;
88 + }
89 cmap.start = 0;
90 - cmap.len = MAX(nr, MAX(ng, nb));
91 - cmap.red = red;
92 - cmap.green = green;
93 - cmap.blue = blue;
94 + cmap.len = n;
95 + cmap.red = map[2];
96 + cmap.green = map[1];
97 + cmap.blue = map[0];
98 cmap.transp = NULL;
100 ioctl(fd, FBIOPUTCMAP, &cmap);
101 @@ -66,25 +82,26 @@
103 unsigned fb_mode(void)
104 {
105 - return (bpp << 16) | (vinfo.red.length << 8) |
106 + return (bytes_per_pixel << 16) | (vinfo.red.length << 8) |
107 (vinfo.green.length << 4) | (vinfo.blue.length);
108 }
110 int fb_init(void)
111 {
112 + int err = 1;
113 fd = open(FBDEV_PATH, O_RDWR);
114 if (fd == -1)
115 goto failed;
116 + err++;
117 if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
118 goto failed;
119 + err++;
120 if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
121 goto failed;
122 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
123 - bpp = (vinfo.bits_per_pixel + 7) >> 3;
124 - nr = 1 << vinfo.red.length;
125 - ng = 1 << vinfo.blue.length;
126 - nb = 1 << vinfo.green.length;
127 + bytes_per_pixel = (vinfo.bits_per_pixel + 7) >> 3;
128 fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
129 + err++;
130 if (fb == MAP_FAILED)
131 goto failed;
132 fb_cmap_save(1);
133 @@ -93,7 +110,7 @@
134 failed:
135 perror("fb_init()");
136 close(fd);
137 - return 1;
138 + return err;
139 }
141 void fb_free(void)
142 @@ -120,19 +137,30 @@
144 void fb_set(int r, int c, void *mem, int len)
145 {
146 - memcpy(fb_mem(r) + (c + vinfo.xoffset) * bpp, mem, len * bpp);
147 + memcpy(fb_mem(r) + (c + vinfo.xoffset) * bytes_per_pixel,
148 + mem, len * bytes_per_pixel);
149 }
151 +void fill_rgb_conv(int mode, struct rgb_conv *s)
152 +{
153 + int bits;
154 +
155 + bits = mode & 0xF; mode >>= 4;
156 + s->rshl = s->gshl = bits;
157 + s->bskp = 8 - bits; s->bmax = (1 << bits) -1;
158 + bits = mode & 0xF; mode >>= 4;
159 + s->rshl += bits;
160 + s->gskp = 8 - bits; s->gmax = (1 << bits) -1;
161 + bits = mode & 0xF;
162 + s->rskp = 8 - bits; s->rmax = (1 << bits) -1;
163 +}
164 +
165 unsigned fb_val(int r, int g, int b)
166 {
167 - switch (fb_mode() & 0x0fff) {
168 - default:
169 - fprintf(stderr, "fb_val: unknown fb_mode()\n");
170 - case 0x0888:
171 - return (r << 16) | (g << 8) | b;
172 - case 0x0565:
173 - return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
174 - case 0x0233:
175 - return ((r >> 6) << 6) | ((g >> 5) << 3) | (b >> 5);
176 - }
177 + static struct rgb_conv c;
178 +
179 + if (c.rshl == 0)
180 + fill_rgb_conv(fb_mode(), &c);
181 + return ((r >> c.rskp) << c.rshl) | ((g >> c.gskp) << c.gshl)
182 + | (b >> c.bskp);
183 }
184 --- fbvnc.c
185 +++ fbvnc.c
186 @@ -36,13 +36,15 @@
188 #define VNC_PORT "5900"
190 -#define MAXRES (1 << 21)
191 -#define MIN(a, b) ((a) < (b) ? (a) : (b))
192 +#define MAXRES (1 << 12)
194 static int cols, rows;
195 +static int srv_cols, srv_rows;
196 +static int or, oc;
197 static int mr, mc; /* mouse position */
199 static char buf[MAXRES];
200 +#define MAXPIX (MAXRES/sizeof(fbval_t))
202 static int vnc_connect(char *addr, char *port)
203 {
204 @@ -61,22 +63,26 @@
206 if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == -1) {
207 close(fd);
208 - freeaddrinfo(addrinfo);
209 - return -1;
210 + fd = -2;
211 }
212 freeaddrinfo(addrinfo);
213 return fd;
214 }
216 +static int bpp, vnc_mode;
217 +static struct rgb_conv format;
218 static int vnc_init(int fd)
219 {
220 - char vncver[] = "RFB 003.003\n";
221 + static int vncfmt[] = { 0x40888, 0x20565, 0x10233, 0 };
222 + char vncver[12];
223 + int i;
224 +
225 struct vnc_client_init clientinit;
226 struct vnc_server_init serverinit;
227 struct vnc_client_pixelfmt pixfmt_cmd;
228 int connstat = VNC_CONN_FAILED;
230 - write(fd, vncver, 12);
231 + write(fd, "RFB 003.003\n", 12);
232 read(fd, vncver, 12);
234 read(fd, &connstat, sizeof(connstat));
235 @@ -88,68 +94,78 @@
236 write(fd, &clientinit, sizeof(clientinit));
237 read(fd, &serverinit, sizeof(serverinit));
239 - if (fb_init())
240 - return -1;
241 - if (FBM_BPP(fb_mode()) != sizeof(fbval_t)) {
242 - fprintf(stderr, "fbvnc: fbval_t doesn't match fb depth\n");
243 - exit(1);
244 - }
245 - cols = MIN(ntohs(serverinit.w), fb_cols());
246 - rows = MIN(ntohs(serverinit.h), fb_rows());
247 + i = fb_init();
248 + if (i)
249 + return -1 - i;
250 + srv_cols = ntohs(serverinit.w);
251 + srv_rows = ntohs(serverinit.h);
252 + cols = MIN(srv_cols, fb_cols());
253 + rows = MIN(srv_rows, fb_rows());
254 mr = rows / 2;
255 mc = cols / 2;
256 + or = oc = 0;
258 read(fd, buf, ntohl(serverinit.len));
259 pixfmt_cmd.type = VNC_CLIENT_PIXFMT;
260 - pixfmt_cmd.format.bpp = 8;
261 - pixfmt_cmd.format.depth = 8;
262 pixfmt_cmd.format.bigendian = 0;
263 pixfmt_cmd.format.truecolor = 1;
265 - pixfmt_cmd.format.rmax = htons(3);
266 - pixfmt_cmd.format.gmax = htons(7);
267 - pixfmt_cmd.format.bmax = htons(7);
268 - pixfmt_cmd.format.rshl = 0;
269 - pixfmt_cmd.format.gshl = 2;
270 - pixfmt_cmd.format.bshl = 5;
271 + if (bpp < 1)
272 + bpp = FBM_BPP(fb_mode());
273 + if (bpp >= 3)
274 + bpp = 4;
275 + for (i = 0; bpp <= FBM_BPP(vncfmt[i]); i++)
276 + vnc_mode = vncfmt[i];
277 + bpp = FBM_BPP(vnc_mode);
278 + pixfmt_cmd.format.bpp =
279 + pixfmt_cmd.format.depth = bpp << 3;
281 + fill_rgb_conv(FBM_COLORS(vnc_mode), &format);
282 + pixfmt_cmd.format.rmax = htons(format.rmax);
283 + pixfmt_cmd.format.gmax = htons(format.gmax);
284 + pixfmt_cmd.format.bmax = htons(format.bmax);
285 + pixfmt_cmd.format.rshl = format.rshl;
286 + pixfmt_cmd.format.gshl = format.gshl;
287 + pixfmt_cmd.format.bshl = 0;
288 write(fd, &pixfmt_cmd, sizeof(pixfmt_cmd));
289 return fd;
290 }
292 -static int vnc_free(void)
293 +static void vnc_free(void)
294 {
295 fb_free();
296 - return 0;
297 }
299 -static int vnc_refresh(int fd, int inc)
300 +static void vnc_refresh(int fd, int inc)
301 {
302 struct vnc_client_fbup fbup_req;
303 fbup_req.type = VNC_CLIENT_FBUP;
304 fbup_req.inc = inc;
305 - fbup_req.x = htons(0);
306 - fbup_req.y = htons(0);
307 - fbup_req.w = htons(cols);
308 - fbup_req.h = htons(rows);
309 + fbup_req.x = htons(oc);
310 + fbup_req.y = htons(or);
311 + fbup_req.w = htons(oc + cols);
312 + fbup_req.h = htons(or + rows);
313 write(fd, &fbup_req, sizeof(fbup_req));
314 - return 0;
315 }
317 -static void drawfb(char *s, int x, int y, int w, int h)
318 +static void drawfb(char *s, int x, int y, int w)
319 {
320 - fbval_t slice[1 << 14];
321 - int i, j;
322 - for (i = 0; i < h; i++) {
323 - for (j = 0; j < w; j++) {
324 - int c = *(unsigned char *) &s[i * w + j];
325 - int r = (c & 0x3) << 6;
326 - int g = ((c >> 2) & 0x7) << 5;
327 - int b = ((c >> 5) & 0x7) << 5;
328 - slice[j] = FB_VAL(r, g, b);
329 + int mode = fb_mode();
330 + if (mode != vnc_mode) {
331 + fbval_t slice[MAXRES];
332 + unsigned char *byte = (unsigned char *) slice;
333 + int j;
334 + int fb_bpp = FBM_BPP(mode);
335 + for (j = 0; j < w; j++, byte += fb_bpp, s += bpp) {
336 + fbval_t c = * (fbval_t *) s;
337 + int r = ((c >> format.rshl) & format.rmax) << format.rskp;
338 + int g = ((c >> format.gshl) & format.gmax) << format.gskp;
339 + int b = (c & format.bmax) << format.bskp;
340 + * (fbval_t *) byte = FB_VAL(r, g, b);
341 }
342 - fb_set(y + i, x, slice, w);
343 + s = (void *) slice;
344 }
345 + fb_set(y, x, s, w);
346 }
348 static void xread(int fd, void *buf, int len)
349 @@ -159,54 +175,84 @@
350 while (nr < len && (n = read(fd, buf + nr, len - nr)) > 0)
351 nr += n;
352 if (nr < len) {
353 - printf("partial vnc read!\n");
354 - exit(1);
355 + fprintf(stderr,"partial vnc read!\n");
356 + exit(99);
357 }
358 }
360 +static void skip(int fd, int len)
361 +{
362 + int n;
363 + while (len > 0 && (n = read(fd, buf, MIN(len, sizeof(buf)))) > 0)
364 + len -= n;
365 +}
366 +
367 static int vnc_event(int fd)
368 {
369 struct vnc_rect uprect;
370 - char msg[1 << 12];
371 - struct vnc_server_fbup *fbup = (void *) msg;
372 - struct vnc_server_cuttext *cuttext = (void *) msg;
373 - struct vnc_server_colormap *colormap = (void *) msg;
374 - int j;
375 - int n;
376 + union {
377 + struct vnc_server_fbup fbup;
378 + struct vnc_server_cuttext cuttext;
379 + struct vnc_server_colormap colormap;
380 + } msg;
381 + int j, n;
383 - if (read(fd, msg, 1) != 1)
384 + if (read(fd, &msg.fbup.type, 1) != 1)
385 return -1;
386 - switch (msg[0]) {
387 + switch (msg.fbup.type) {
388 case VNC_SERVER_FBUP:
389 - xread(fd, msg + 1, sizeof(*fbup) - 1);
390 - n = ntohs(fbup->n);
391 + xread(fd, &msg.fbup.pad, sizeof(msg.fbup) - 1);
392 + n = ntohs(msg.fbup.n);
393 for (j = 0; j < n; j++) {
394 - int x, y, w, h;
395 + int x, y, w, h, l, i;
396 xread(fd, &uprect, sizeof(uprect));
397 + if (uprect.enc != 0) {
398 + fprintf(stderr,"Encoding not RAW: %d\n",
399 + ntohl(uprect.enc));
400 + return -1;
401 + }
402 x = ntohs(uprect.x);
403 y = ntohs(uprect.y);
404 w = ntohs(uprect.w);
405 h = ntohs(uprect.h);
406 - if (x >= cols || x + w > cols)
407 - return -1;
408 - if (y >= rows || y + h > rows)
409 - return -1;
410 - xread(fd, buf, w * h);
411 - drawfb(buf, x, y, w, h);
412 + x -= oc;
413 + y -= or;
414 + i = 0;
415 + l = MIN(w, cols - x);
416 + if (x < 0) {
417 + l = MIN(w + x, cols);
418 + i = MIN(w, -x);
419 + x = 0;
420 + }
421 + if (l < 0)
422 + l = 0;
423 + for (; h--; y++) {
424 + int n = l;
425 + int xj = x;
426 + skip(fd, i * bpp);
427 + while (n > 0) {
428 + int j = MIN(n, MAXPIX);
429 + xread(fd, buf, j * bpp);
430 + if (y >= 0 && y < rows)
431 + drawfb(buf, xj, y, j);
432 + xj += j; n -= j;
433 + }
434 + skip(fd, (w - l - i) * bpp);
435 + }
436 }
437 break;
438 case VNC_SERVER_BELL:
439 break;
440 case VNC_SERVER_CUTTEXT:
441 - xread(fd, msg + 1, sizeof(*cuttext) - 1);
442 - xread(fd, buf, ntohl(cuttext->len));
443 + xread(fd, &msg.cuttext.pad1, sizeof(msg.cuttext) - 1);
444 + skip(fd, ntohl(msg.cuttext.len));
445 break;
446 case VNC_SERVER_COLORMAP:
447 - xread(fd, msg + 1, sizeof(*colormap) - 1);
448 - xread(fd, buf, ntohs(colormap->n) * 3 * 2);
449 + xread(fd, &msg.colormap.pad, sizeof(msg.colormap) - 1);
450 + skip(fd, ntohs(msg.colormap.n) * 3 * 2);
451 break;
452 default:
453 - fprintf(stderr, "unknown vnc msg: %d\n", msg[0]);
454 + fprintf(stderr, "unknown vnc msg: %d\n", msg.fbup.type);
455 return -1;
456 }
457 return 0;
458 @@ -217,12 +263,31 @@
459 char ie[3];
460 struct vnc_client_ratevent me = {VNC_CLIENT_RATEVENT};
461 int mask = 0;
462 + int refresh = 2;
463 if (read(ratfd, &ie, sizeof(ie)) != 3)
464 return -1;
465 mc += ie[1];
466 mr -= ie[2];
467 - mc = MAX(0, MIN(cols - 1, mc));
468 - mr = MAX(0, MIN(rows - 1, mr));
469 + if (mc < oc) {
470 + if ((oc -= cols / 5) < 0)
471 + oc = 0;
472 + }
473 + else if (mc >= oc + cols && oc + cols < srv_cols) {
474 + if ((oc += cols / 5) > srv_cols - cols)
475 + oc = srv_cols - cols;
476 + }
477 + else refresh--;
478 + if (mr < or) {
479 + if ((or -= rows / 5) < 0)
480 + or = 0;
481 + }
482 + else if (mr >= or + rows && or + rows < srv_rows) {
483 + if ((or += rows / 5) > srv_rows - rows)
484 + or = srv_rows - rows;
485 + }
486 + else refresh--;
487 + mc = MAX(oc, MIN(oc + cols - 1, mc));
488 + mr = MAX(or, MIN(or + rows - 1, mr));
489 if (ie[0] & 0x01)
490 mask |= VNC_BUTTON1_MASK;
491 if (ie[0] & 0x04)
492 @@ -233,6 +298,8 @@
493 me.x = htons(mc);
494 me.mask = mask;
495 write(fd, &me, sizeof(me));
496 + if (refresh)
497 + vnc_refresh(fd, 0);
498 return 0;
499 }
501 @@ -292,12 +359,11 @@
502 k = 0xff0d;
503 break;
504 case 0x0c: /* ^L: redraw */
505 - if (vnc_refresh(fd, 0))
506 - return -1;
507 + vnc_refresh(fd, 0);
508 default:
509 k = (unsigned char) key[i];
510 }
511 - if (k >= 'A' && k <= 'Z' || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
512 + if ((k >= 'A' && k <= 'Z') || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
513 mod[nmod++] = 0xffe1;
514 if (k >= 1 && k <= 26) {
515 k = 'a' + k - 1;
516 @@ -339,40 +405,42 @@
517 write(STDIN_FILENO, show, strlen(show));
518 }
520 -static void mainloop(int vnc_fd, int kbd_fd, int rat_fd)
521 +static int mainloop(int vnc_fd, int kbd_fd, int rat_fd)
522 {
523 struct pollfd ufds[3];
524 int pending = 0;
525 int err;
526 ufds[0].fd = kbd_fd;
527 - ufds[0].events = POLLIN;
528 ufds[1].fd = vnc_fd;
529 - ufds[1].events = POLLIN;
530 ufds[2].fd = rat_fd;
531 + ufds[0].events =
532 + ufds[1].events =
533 ufds[2].events = POLLIN;
534 - if (vnc_refresh(vnc_fd, 0))
535 - return;
536 + vnc_refresh(vnc_fd, 0);
537 while (1) {
538 err = poll(ufds, 3, 500);
539 if (err == -1 && errno != EINTR)
540 break;
541 if (!err)
542 continue;
543 + err = -2;
544 if (ufds[0].revents & POLLIN)
545 if (kbd_event(vnc_fd, kbd_fd) == -1)
546 break;
547 + err--;
548 if (ufds[1].revents & POLLIN) {
549 if (vnc_event(vnc_fd) == -1)
550 break;
551 pending = 0;
552 }
553 + err--;
554 if (ufds[2].revents & POLLIN)
555 if (rat_event(vnc_fd, rat_fd) == -1)
556 break;
557 if (!pending++)
558 - if (vnc_refresh(vnc_fd, 1))
559 - break;
560 + vnc_refresh(vnc_fd, 1);
561 }
562 + return err;
563 }
565 int main(int argc, char * argv[])
566 @@ -380,27 +448,38 @@
567 char *port = VNC_PORT;
568 char *host = "127.0.0.1";
569 struct termios ti;
570 - int vnc_fd, rat_fd;
571 + int vnc_fd, rat_fd, status;
572 +
573 + if (argc < 2) {
574 + fprintf(stderr, "Usage : fbvnc [-bpp bits] server [port]\n");
575 + return 0;
576 + }
577 + if (*argv[1] == '-' && argc >= 3) {
578 + argc -= 2; argv += 2;
579 + bpp = atoi(argv[0]) >> 3;
580 + }
581 if (argc >= 2)
582 host = argv[1];
583 if (argc >= 3)
584 port = argv[2];
585 - if ((vnc_fd = vnc_connect(host, port)) == -1) {
586 - fprintf(stderr, "could not connect!\n");
587 + if ((vnc_fd = vnc_connect(host, port)) < 0) {
588 + fprintf(stderr, "could not connect! %s %s : %d\n",
589 + host,port,vnc_fd);
590 return 1;
591 }
592 - if (vnc_init(vnc_fd) == -1) {
593 - fprintf(stderr, "vnc init failed!\n");
594 - return 1;
595 + status = vnc_init(vnc_fd);
596 + if (status < 0) {
597 + fprintf(stderr, "vnc init failed! %d\n", status);
598 + return 2;
599 }
600 term_setup(&ti);
601 rat_fd = open("/dev/input/mice", O_RDONLY);
603 - mainloop(vnc_fd, 0, rat_fd);
604 + status = mainloop(vnc_fd, 0, rat_fd);
606 term_cleanup(&ti);
607 vnc_free();
608 close(vnc_fd);
609 close(rat_fd);
610 - return 0;
611 + return 2 - status;
612 }