wok-current diff fbvnc/stuff/fbvnc.u @ rev 18127

marco: update deps
author Yuri Pourre <yuripourre@gmail.com>
date Thu Jun 11 13:30:44 2015 -0300 (2015-06-11)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/fbvnc/stuff/fbvnc.u	Thu Jun 11 13:30:44 2015 -0300
     1.3 @@ -0,0 +1,612 @@
     1.4 +--- draw.h
     1.5 ++++ draw.h
     1.6 +@@ -15,5 +15,11 @@
     1.7 + void fb_cmap(void);
     1.8 + 
     1.9 + /* helper functions */
    1.10 ++struct rgb_conv {
    1.11 ++	int rshl, gshl;
    1.12 ++	int rskp, gskp, bskp;
    1.13 ++	int rmax, gmax, bmax;
    1.14 ++};
    1.15 ++void fill_rgb_conv(int mode, struct rgb_conv *s);
    1.16 + void fb_set(int r, int c, void *mem, int len);
    1.17 + unsigned fb_val(int r, int g, int b);
    1.18 +--- draw.c
    1.19 ++++ draw.c
    1.20 +@@ -10,14 +10,13 @@
    1.21 + 
    1.22 + #define MIN(a, b)	((a) < (b) ? (a) : (b))
    1.23 + #define MAX(a, b)	((a) > (b) ? (a) : (b))
    1.24 +-#define NLEVELS		(1 << 8)
    1.25 ++#define NLEVELS		(1 << 16)
    1.26 + 
    1.27 + static int fd;
    1.28 + static void *fb;
    1.29 + static struct fb_var_screeninfo vinfo;
    1.30 + static struct fb_fix_screeninfo finfo;
    1.31 +-static int bpp;
    1.32 +-static int nr, ng, nb;
    1.33 ++static int bytes_per_pixel;
    1.34 + 
    1.35 + static int fb_len(void)
    1.36 + {
    1.37 +@@ -28,10 +27,12 @@
    1.38 + {
    1.39 + 	static unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
    1.40 + 	struct fb_cmap cmap;
    1.41 ++
    1.42 + 	if (finfo.visual == FB_VISUAL_TRUECOLOR)
    1.43 + 		return;
    1.44 ++
    1.45 + 	cmap.start = 0;
    1.46 +-	cmap.len = MAX(nr, MAX(ng, nb));
    1.47 ++	cmap.len = NLEVELS;
    1.48 + 	cmap.red = red;
    1.49 + 	cmap.green = green;
    1.50 + 	cmap.blue = blue;
    1.51 +@@ -41,24 +42,39 @@
    1.52 + 
    1.53 + void fb_cmap(void)
    1.54 + {
    1.55 +-	unsigned short red[NLEVELS], green[NLEVELS], blue[NLEVELS];
    1.56 ++	struct fb_bitfield *color[3] = {
    1.57 ++		&vinfo.blue, &vinfo.green, &vinfo.red
    1.58 ++	};
    1.59 ++	int eye_sensibility[3] = { 2, 0, 1 }; // higher=red, blue, lower=green
    1.60 + 	struct fb_cmap cmap;
    1.61 +-	int i;
    1.62 ++	unsigned short map[3][NLEVELS];
    1.63 ++	int i, j, n, offset;
    1.64 ++
    1.65 + 	if (finfo.visual == FB_VISUAL_TRUECOLOR)
    1.66 + 		return;
    1.67 + 
    1.68 +-	for (i = 0; i < nr; i++)
    1.69 +-		red[i] = (65535 / (nr - 1)) * i;
    1.70 +-	for (i = 0; i < ng; i++)
    1.71 +-		green[i] = (65535 / (ng - 1)) * i;
    1.72 +-	for (i = 0; i < nb; i++)
    1.73 +-		blue[i] = (65535 / (nb - 1)) * i;
    1.74 +-
    1.75 ++	for (i = 0, n = vinfo.bits_per_pixel; i < 3; i++) {
    1.76 ++		n -= color[eye_sensibility[i]]->length = n / (3 - i);
    1.77 ++	}
    1.78 ++	n = (1 << vinfo.bits_per_pixel);
    1.79 ++	if (n > NLEVELS)
    1.80 ++		n = NLEVELS;
    1.81 ++	for (i = offset = 0; i < 3; i++) {
    1.82 ++		int length = color[i]->length;
    1.83 ++		color[i]->offset = offset;
    1.84 ++		for (j = 0; j < n; j++) {
    1.85 ++			int k = (j >> offset) << (16 - length);
    1.86 ++			if (k == (0xFFFF << (16 - length)))
    1.87 ++				k = 0xFFFF;
    1.88 ++			map[i][j] = k;
    1.89 ++		}
    1.90 ++		offset += length;
    1.91 ++	}
    1.92 + 	cmap.start = 0;
    1.93 +-	cmap.len = MAX(nr, MAX(ng, nb));
    1.94 +-	cmap.red = red;
    1.95 +-	cmap.green = green;
    1.96 +-	cmap.blue = blue;
    1.97 ++	cmap.len = n;
    1.98 ++	cmap.red = map[2];
    1.99 ++	cmap.green = map[1];
   1.100 ++	cmap.blue = map[0];
   1.101 + 	cmap.transp = NULL;
   1.102 + 
   1.103 + 	ioctl(fd, FBIOPUTCMAP, &cmap);
   1.104 +@@ -66,25 +82,26 @@
   1.105 + 
   1.106 + unsigned fb_mode(void)
   1.107 + {
   1.108 +-	return (bpp << 16) | (vinfo.red.length << 8) |
   1.109 ++	return (bytes_per_pixel << 16) | (vinfo.red.length << 8) |
   1.110 + 		(vinfo.green.length << 4) | (vinfo.blue.length);
   1.111 + }
   1.112 + 
   1.113 + int fb_init(void)
   1.114 + {
   1.115 ++	int err = 1;
   1.116 + 	fd = open(FBDEV_PATH, O_RDWR);
   1.117 + 	if (fd == -1)
   1.118 + 		goto failed;
   1.119 ++	err++;
   1.120 + 	if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
   1.121 + 		goto failed;
   1.122 ++	err++;
   1.123 + 	if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1)
   1.124 + 		goto failed;
   1.125 + 	fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
   1.126 +-	bpp = (vinfo.bits_per_pixel + 7) >> 3;
   1.127 +-	nr = 1 << vinfo.red.length;
   1.128 +-	ng = 1 << vinfo.blue.length;
   1.129 +-	nb = 1 << vinfo.green.length;
   1.130 ++	bytes_per_pixel = (vinfo.bits_per_pixel + 7) >> 3;
   1.131 + 	fb = mmap(NULL, fb_len(), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
   1.132 ++	err++;
   1.133 + 	if (fb == MAP_FAILED)
   1.134 + 		goto failed;
   1.135 + 	fb_cmap_save(1);
   1.136 +@@ -93,7 +110,7 @@
   1.137 + failed:
   1.138 + 	perror("fb_init()");
   1.139 + 	close(fd);
   1.140 +-	return 1;
   1.141 ++	return err;
   1.142 + }
   1.143 + 
   1.144 + void fb_free(void)
   1.145 +@@ -120,19 +137,30 @@
   1.146 + 
   1.147 + void fb_set(int r, int c, void *mem, int len)
   1.148 + {
   1.149 +-	memcpy(fb_mem(r) + (c + vinfo.xoffset) * bpp, mem, len * bpp);
   1.150 ++	memcpy(fb_mem(r) + (c + vinfo.xoffset) * bytes_per_pixel,
   1.151 ++		mem, len * bytes_per_pixel);
   1.152 + }
   1.153 + 
   1.154 ++void fill_rgb_conv(int mode, struct rgb_conv *s)
   1.155 ++{
   1.156 ++	int bits;
   1.157 ++
   1.158 ++	bits = mode & 0xF;  mode >>= 4;
   1.159 ++	s->rshl = s->gshl = bits;
   1.160 ++	s->bskp = 8 - bits; s->bmax = (1 << bits) -1;
   1.161 ++	bits = mode & 0xF;  mode >>= 4;
   1.162 ++	s->rshl += bits;
   1.163 ++	s->gskp = 8 - bits; s->gmax = (1 << bits) -1;
   1.164 ++	bits = mode & 0xF;
   1.165 ++	s->rskp = 8 - bits; s->rmax = (1 << bits) -1;
   1.166 ++}
   1.167 ++
   1.168 + unsigned fb_val(int r, int g, int b)
   1.169 + {
   1.170 +-	switch (fb_mode() & 0x0fff) {
   1.171 +-	default:
   1.172 +-		fprintf(stderr, "fb_val: unknown fb_mode()\n");
   1.173 +-	case 0x0888:
   1.174 +-		return (r << 16) | (g << 8) | b;
   1.175 +-	case 0x0565:
   1.176 +-		return ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
   1.177 +-	case 0x0233:
   1.178 +-		return ((r >> 6) << 6) | ((g >> 5) << 3) | (b >> 5);
   1.179 +-	}
   1.180 ++	static struct rgb_conv c;
   1.181 ++	
   1.182 ++	if (c.rshl == 0)
   1.183 ++		fill_rgb_conv(fb_mode(), &c);
   1.184 ++	return ((r >> c.rskp) << c.rshl) | ((g >> c.gskp) << c.gshl) 
   1.185 ++					 | (b >> c.bskp);
   1.186 + }
   1.187 +--- fbvnc.c
   1.188 ++++ fbvnc.c
   1.189 +@@ -36,13 +36,15 @@
   1.190 + 
   1.191 + #define VNC_PORT		"5900"
   1.192 + 
   1.193 +-#define MAXRES			(1 << 21)
   1.194 +-#define MIN(a, b)		((a) < (b) ? (a) : (b))
   1.195 ++#define MAXRES			(1 << 12)
   1.196 + 
   1.197 + static int cols, rows;
   1.198 ++static int srv_cols, srv_rows;
   1.199 ++static int or, oc;
   1.200 + static int mr, mc;		/* mouse position */
   1.201 + 
   1.202 + static char buf[MAXRES];
   1.203 ++#define MAXPIX		(MAXRES/sizeof(fbval_t))
   1.204 + 
   1.205 + static int vnc_connect(char *addr, char *port)
   1.206 + {
   1.207 +@@ -61,22 +63,26 @@
   1.208 + 
   1.209 + 	if (connect(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) == -1) {
   1.210 + 		close(fd);
   1.211 +-		freeaddrinfo(addrinfo);
   1.212 +-		return -1;
   1.213 ++		fd = -2;
   1.214 + 	}
   1.215 + 	freeaddrinfo(addrinfo);
   1.216 + 	return fd;
   1.217 + }
   1.218 + 
   1.219 ++static int bpp, vnc_mode;
   1.220 ++static struct rgb_conv format;
   1.221 + static int vnc_init(int fd)
   1.222 + {
   1.223 +-	char vncver[] = "RFB 003.003\n";
   1.224 ++	static int vncfmt[] = { 0x40888, 0x20565, 0x10233, 0 };
   1.225 ++	char vncver[12];
   1.226 ++	int i;
   1.227 ++
   1.228 + 	struct vnc_client_init clientinit;
   1.229 + 	struct vnc_server_init serverinit;
   1.230 + 	struct vnc_client_pixelfmt pixfmt_cmd;
   1.231 + 	int connstat = VNC_CONN_FAILED;
   1.232 + 
   1.233 +-	write(fd, vncver, 12);
   1.234 ++	write(fd, "RFB 003.003\n", 12);
   1.235 + 	read(fd, vncver, 12);
   1.236 + 
   1.237 + 	read(fd, &connstat, sizeof(connstat));
   1.238 +@@ -88,68 +94,78 @@
   1.239 + 	write(fd, &clientinit, sizeof(clientinit));
   1.240 + 	read(fd, &serverinit, sizeof(serverinit));
   1.241 + 
   1.242 +-	if (fb_init())
   1.243 +-		return -1;
   1.244 +-	if (FBM_BPP(fb_mode()) != sizeof(fbval_t)) {
   1.245 +-		fprintf(stderr, "fbvnc: fbval_t doesn't match fb depth\n");
   1.246 +-		exit(1);
   1.247 +-	}
   1.248 +-	cols = MIN(ntohs(serverinit.w), fb_cols());
   1.249 +-	rows = MIN(ntohs(serverinit.h), fb_rows());
   1.250 ++	i = fb_init();
   1.251 ++	if (i)
   1.252 ++		return -1 - i;
   1.253 ++	srv_cols = ntohs(serverinit.w);
   1.254 ++	srv_rows = ntohs(serverinit.h);
   1.255 ++	cols = MIN(srv_cols, fb_cols());
   1.256 ++	rows = MIN(srv_rows, fb_rows());
   1.257 + 	mr = rows / 2;
   1.258 + 	mc = cols / 2;
   1.259 ++	or = oc = 0;
   1.260 + 
   1.261 + 	read(fd, buf, ntohl(serverinit.len));
   1.262 + 	pixfmt_cmd.type = VNC_CLIENT_PIXFMT;
   1.263 +-	pixfmt_cmd.format.bpp = 8;
   1.264 +-	pixfmt_cmd.format.depth = 8;
   1.265 + 	pixfmt_cmd.format.bigendian = 0;
   1.266 + 	pixfmt_cmd.format.truecolor = 1;
   1.267 + 
   1.268 +-	pixfmt_cmd.format.rmax = htons(3);
   1.269 +-	pixfmt_cmd.format.gmax = htons(7);
   1.270 +-	pixfmt_cmd.format.bmax = htons(7);
   1.271 +-	pixfmt_cmd.format.rshl = 0;
   1.272 +-	pixfmt_cmd.format.gshl = 2;
   1.273 +-	pixfmt_cmd.format.bshl = 5;
   1.274 ++	if (bpp < 1)
   1.275 ++	  	bpp = FBM_BPP(fb_mode());
   1.276 ++	if (bpp >= 3)
   1.277 ++		bpp = 4;
   1.278 ++	for (i = 0; bpp <= FBM_BPP(vncfmt[i]); i++)
   1.279 ++		vnc_mode = vncfmt[i];
   1.280 ++	bpp = FBM_BPP(vnc_mode);
   1.281 ++	pixfmt_cmd.format.bpp =
   1.282 ++	pixfmt_cmd.format.depth = bpp << 3;
   1.283 + 
   1.284 ++	fill_rgb_conv(FBM_COLORS(vnc_mode), &format);
   1.285 ++	pixfmt_cmd.format.rmax = htons(format.rmax);
   1.286 ++	pixfmt_cmd.format.gmax = htons(format.gmax);
   1.287 ++	pixfmt_cmd.format.bmax = htons(format.bmax);
   1.288 ++	pixfmt_cmd.format.rshl = format.rshl;
   1.289 ++	pixfmt_cmd.format.gshl = format.gshl;
   1.290 ++	pixfmt_cmd.format.bshl = 0;
   1.291 + 	write(fd, &pixfmt_cmd, sizeof(pixfmt_cmd));
   1.292 + 	return fd;
   1.293 + }
   1.294 + 
   1.295 +-static int vnc_free(void)
   1.296 ++static void vnc_free(void)
   1.297 + {
   1.298 + 	fb_free();
   1.299 +-	return 0;
   1.300 + }
   1.301 + 
   1.302 +-static int vnc_refresh(int fd, int inc)
   1.303 ++static void vnc_refresh(int fd, int inc)
   1.304 + {
   1.305 + 	struct vnc_client_fbup fbup_req;
   1.306 + 	fbup_req.type = VNC_CLIENT_FBUP;
   1.307 + 	fbup_req.inc = inc;
   1.308 +-	fbup_req.x = htons(0);
   1.309 +-	fbup_req.y = htons(0);
   1.310 +-	fbup_req.w = htons(cols);
   1.311 +-	fbup_req.h = htons(rows);
   1.312 ++	fbup_req.x = htons(oc);
   1.313 ++	fbup_req.y = htons(or);
   1.314 ++	fbup_req.w = htons(oc + cols);
   1.315 ++	fbup_req.h = htons(or + rows);
   1.316 + 	write(fd, &fbup_req, sizeof(fbup_req));
   1.317 +-	return 0;
   1.318 + }
   1.319 + 
   1.320 +-static void drawfb(char *s, int x, int y, int w, int h)
   1.321 ++static void drawfb(char *s, int x, int y, int w)
   1.322 + {
   1.323 +-	fbval_t slice[1 << 14];
   1.324 +-	int i, j;
   1.325 +-	for (i = 0; i < h; i++) {
   1.326 +-		for (j = 0; j < w; j++) {
   1.327 +-			int c = *(unsigned char *) &s[i * w + j];
   1.328 +-			int r = (c & 0x3) << 6;
   1.329 +-			int g = ((c >> 2) & 0x7) << 5;
   1.330 +-			int b = ((c >> 5) & 0x7) << 5;
   1.331 +-			slice[j] = FB_VAL(r, g, b);
   1.332 ++	int mode = fb_mode();
   1.333 ++	if (mode != vnc_mode) {
   1.334 ++		fbval_t slice[MAXRES];
   1.335 ++		unsigned char *byte = (unsigned char *) slice;
   1.336 ++		int j;
   1.337 ++		int fb_bpp = FBM_BPP(mode);
   1.338 ++		for (j = 0; j < w; j++, byte += fb_bpp, s += bpp) {
   1.339 ++			fbval_t c = * (fbval_t *) s;
   1.340 ++			int r = ((c >> format.rshl) & format.rmax) << format.rskp;
   1.341 ++			int g = ((c >> format.gshl) & format.gmax) << format.gskp;
   1.342 ++			int b = (c & format.bmax) << format.bskp;
   1.343 ++			* (fbval_t *) byte = FB_VAL(r, g, b);
   1.344 + 		}
   1.345 +-		fb_set(y + i, x, slice, w);
   1.346 ++		s = (void *) slice;
   1.347 + 	}
   1.348 ++	fb_set(y, x, s, w);
   1.349 + }
   1.350 + 
   1.351 + static void xread(int fd, void *buf, int len)
   1.352 +@@ -159,54 +175,84 @@
   1.353 + 	while (nr < len && (n = read(fd, buf + nr, len - nr)) > 0)
   1.354 + 		nr += n;
   1.355 + 	if (nr < len) {
   1.356 +-		printf("partial vnc read!\n");
   1.357 +-		exit(1);
   1.358 ++		fprintf(stderr,"partial vnc read!\n");
   1.359 ++		exit(99);
   1.360 + 	}
   1.361 + }
   1.362 + 
   1.363 ++static void skip(int fd, int len)
   1.364 ++{
   1.365 ++	int n;
   1.366 ++	while (len > 0 && (n = read(fd, buf, MIN(len, sizeof(buf)))) > 0)
   1.367 ++		len -= n;
   1.368 ++}
   1.369 ++
   1.370 + static int vnc_event(int fd)
   1.371 + {
   1.372 + 	struct vnc_rect uprect;
   1.373 +-	char msg[1 << 12];
   1.374 +-	struct vnc_server_fbup *fbup = (void *) msg;
   1.375 +-	struct vnc_server_cuttext *cuttext = (void *) msg;
   1.376 +-	struct vnc_server_colormap *colormap = (void *) msg;
   1.377 +-	int j;
   1.378 +-	int n;
   1.379 ++	union {
   1.380 ++		struct vnc_server_fbup fbup;
   1.381 ++		struct vnc_server_cuttext cuttext;
   1.382 ++		struct vnc_server_colormap colormap;
   1.383 ++	} msg;
   1.384 ++	int j, n;
   1.385 + 
   1.386 +-	if (read(fd, msg, 1) != 1)
   1.387 ++	if (read(fd, &msg.fbup.type, 1) != 1)
   1.388 + 		return -1;
   1.389 +-	switch (msg[0]) {
   1.390 ++	switch (msg.fbup.type) {
   1.391 + 	case VNC_SERVER_FBUP:
   1.392 +-		xread(fd, msg + 1, sizeof(*fbup) - 1);
   1.393 +-		n = ntohs(fbup->n);
   1.394 ++		xread(fd, &msg.fbup.pad, sizeof(msg.fbup) - 1);
   1.395 ++		n = ntohs(msg.fbup.n);
   1.396 + 		for (j = 0; j < n; j++) {
   1.397 +-			int x, y, w, h;
   1.398 ++			int x, y, w, h, l, i;
   1.399 + 			xread(fd, &uprect, sizeof(uprect));
   1.400 ++			if (uprect.enc != 0) {
   1.401 ++				fprintf(stderr,"Encoding not RAW: %d\n",
   1.402 ++					ntohl(uprect.enc));
   1.403 ++				return -1;
   1.404 ++			}
   1.405 + 			x = ntohs(uprect.x);
   1.406 + 			y = ntohs(uprect.y);
   1.407 + 			w = ntohs(uprect.w);
   1.408 + 			h = ntohs(uprect.h);
   1.409 +-			if (x >= cols || x + w > cols)
   1.410 +-				return -1;
   1.411 +-			if (y >= rows || y + h > rows)
   1.412 +-				return -1;
   1.413 +-			xread(fd, buf, w * h);
   1.414 +-			drawfb(buf, x, y, w, h);
   1.415 ++			x -= oc;
   1.416 ++			y -= or;
   1.417 ++			i = 0;
   1.418 ++			l = MIN(w, cols - x);
   1.419 ++			if (x < 0) {
   1.420 ++				l = MIN(w + x, cols);
   1.421 ++				i = MIN(w, -x);
   1.422 ++				x = 0;
   1.423 ++			}
   1.424 ++			if (l < 0)
   1.425 ++				l = 0;
   1.426 ++			for (; h--; y++) {
   1.427 ++				int n = l;
   1.428 ++				int xj = x;
   1.429 ++				skip(fd, i * bpp);
   1.430 ++				while (n > 0) {
   1.431 ++					int j = MIN(n, MAXPIX);
   1.432 ++					xread(fd, buf, j * bpp);
   1.433 ++					if (y >= 0 && y < rows)
   1.434 ++						drawfb(buf, xj, y, j);
   1.435 ++					xj += j; n -= j;
   1.436 ++				}
   1.437 ++				skip(fd, (w - l - i) * bpp);
   1.438 ++			}
   1.439 + 		}
   1.440 + 		break;
   1.441 + 	case VNC_SERVER_BELL:
   1.442 + 		break;
   1.443 + 	case VNC_SERVER_CUTTEXT:
   1.444 +-		xread(fd, msg + 1, sizeof(*cuttext) - 1);
   1.445 +-		xread(fd, buf, ntohl(cuttext->len));
   1.446 ++		xread(fd, &msg.cuttext.pad1, sizeof(msg.cuttext) - 1);
   1.447 ++		skip(fd, ntohl(msg.cuttext.len));
   1.448 + 		break;
   1.449 + 	case VNC_SERVER_COLORMAP:
   1.450 +-		xread(fd, msg + 1, sizeof(*colormap) - 1);
   1.451 +-		xread(fd, buf, ntohs(colormap->n) * 3 * 2);
   1.452 ++		xread(fd, &msg.colormap.pad, sizeof(msg.colormap) - 1);
   1.453 ++		skip(fd, ntohs(msg.colormap.n) * 3 * 2);
   1.454 + 		break;
   1.455 + 	default:
   1.456 +-		fprintf(stderr, "unknown vnc msg: %d\n", msg[0]);
   1.457 ++		fprintf(stderr, "unknown vnc msg: %d\n", msg.fbup.type);
   1.458 + 		return -1;
   1.459 + 	}
   1.460 + 	return 0;
   1.461 +@@ -217,12 +263,31 @@
   1.462 + 	char ie[3];
   1.463 + 	struct vnc_client_ratevent me = {VNC_CLIENT_RATEVENT};
   1.464 + 	int mask = 0;
   1.465 ++	int refresh = 2;
   1.466 + 	if (read(ratfd, &ie, sizeof(ie)) != 3)
   1.467 + 		return -1;
   1.468 + 	mc += ie[1];
   1.469 + 	mr -= ie[2];
   1.470 +-	mc = MAX(0, MIN(cols - 1, mc));
   1.471 +-	mr = MAX(0, MIN(rows - 1, mr));
   1.472 ++	if (mc < oc) {
   1.473 ++		if ((oc -= cols / 5) < 0)
   1.474 ++			oc = 0;
   1.475 ++	}
   1.476 ++	else if (mc >= oc + cols && oc + cols < srv_cols) {
   1.477 ++		if ((oc += cols / 5) > srv_cols - cols)
   1.478 ++			oc = srv_cols - cols;
   1.479 ++	}
   1.480 ++	else refresh--;
   1.481 ++	if (mr < or) {
   1.482 ++		if ((or -= rows / 5) < 0)
   1.483 ++			or = 0;
   1.484 ++	}
   1.485 ++	else if (mr >= or + rows && or + rows < srv_rows) {
   1.486 ++		if ((or += rows / 5) > srv_rows - rows)
   1.487 ++			or = srv_rows - rows;
   1.488 ++	}
   1.489 ++	else refresh--;
   1.490 ++	mc = MAX(oc, MIN(oc + cols - 1, mc));
   1.491 ++	mr = MAX(or, MIN(or + rows - 1, mr));
   1.492 + 	if (ie[0] & 0x01)
   1.493 + 		mask |= VNC_BUTTON1_MASK;
   1.494 + 	if (ie[0] & 0x04)
   1.495 +@@ -233,6 +298,8 @@
   1.496 + 	me.x = htons(mc);
   1.497 + 	me.mask = mask;
   1.498 + 	write(fd, &me, sizeof(me));
   1.499 ++	if (refresh)
   1.500 ++		vnc_refresh(fd, 0);
   1.501 + 	return 0;
   1.502 + }
   1.503 + 
   1.504 +@@ -292,12 +359,11 @@
   1.505 + 			k = 0xff0d;
   1.506 + 			break;
   1.507 + 		case 0x0c:	/* ^L: redraw */
   1.508 +-			if (vnc_refresh(fd, 0))
   1.509 +-				return -1;
   1.510 ++			vnc_refresh(fd, 0);
   1.511 + 		default:
   1.512 + 			k = (unsigned char) key[i];
   1.513 + 		}
   1.514 +-		if (k >= 'A' && k <= 'Z' || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
   1.515 ++		if ((k >= 'A' && k <= 'Z') || strchr(":\"<>?{}|+_()*&^%$#@!~", k))
   1.516 + 			mod[nmod++] = 0xffe1;
   1.517 + 		if (k >= 1 && k <= 26) {
   1.518 + 			k = 'a' + k - 1;
   1.519 +@@ -339,40 +405,42 @@
   1.520 + 	write(STDIN_FILENO, show, strlen(show));
   1.521 + }
   1.522 + 
   1.523 +-static void mainloop(int vnc_fd, int kbd_fd, int rat_fd)
   1.524 ++static int mainloop(int vnc_fd, int kbd_fd, int rat_fd)
   1.525 + {
   1.526 + 	struct pollfd ufds[3];
   1.527 + 	int pending = 0;
   1.528 + 	int err;
   1.529 + 	ufds[0].fd = kbd_fd;
   1.530 +-	ufds[0].events = POLLIN;
   1.531 + 	ufds[1].fd = vnc_fd;
   1.532 +-	ufds[1].events = POLLIN;
   1.533 + 	ufds[2].fd = rat_fd;
   1.534 ++	ufds[0].events =
   1.535 ++	ufds[1].events =
   1.536 + 	ufds[2].events = POLLIN;
   1.537 +-	if (vnc_refresh(vnc_fd, 0))
   1.538 +-		return;
   1.539 ++	vnc_refresh(vnc_fd, 0);
   1.540 + 	while (1) {
   1.541 + 		err = poll(ufds, 3, 500);
   1.542 + 		if (err == -1 && errno != EINTR)
   1.543 + 			break;
   1.544 + 		if (!err)
   1.545 + 			continue;
   1.546 ++		err = -2;
   1.547 + 		if (ufds[0].revents & POLLIN)
   1.548 + 			if (kbd_event(vnc_fd, kbd_fd) == -1)
   1.549 + 				break;
   1.550 ++		err--;
   1.551 + 		if (ufds[1].revents & POLLIN) {
   1.552 + 			if (vnc_event(vnc_fd) == -1)
   1.553 + 				break;
   1.554 + 			pending = 0;
   1.555 + 		}
   1.556 ++		err--;
   1.557 + 		if (ufds[2].revents & POLLIN)
   1.558 + 			if (rat_event(vnc_fd, rat_fd) == -1)
   1.559 + 				break;
   1.560 + 		if (!pending++)
   1.561 +-			if (vnc_refresh(vnc_fd, 1))
   1.562 +-				break;
   1.563 ++			vnc_refresh(vnc_fd, 1);
   1.564 + 	}
   1.565 ++	return err;
   1.566 + }
   1.567 + 
   1.568 + int main(int argc, char * argv[])
   1.569 +@@ -380,27 +448,38 @@
   1.570 + 	char *port = VNC_PORT;
   1.571 + 	char *host = "127.0.0.1";
   1.572 + 	struct termios ti;
   1.573 +-	int vnc_fd, rat_fd;
   1.574 ++	int vnc_fd, rat_fd, status;
   1.575 ++	
   1.576 ++	if (argc < 2) {
   1.577 ++		fprintf(stderr, "Usage : fbvnc [-bpp bits] server [port]\n");
   1.578 ++		return 0;
   1.579 ++  	}
   1.580 ++  	if (*argv[1] == '-' && argc >= 3) {
   1.581 ++  		argc -= 2; argv += 2;
   1.582 ++  		bpp = atoi(argv[0]) >> 3;
   1.583 ++  	} 
   1.584 + 	if (argc >= 2)
   1.585 + 		host = argv[1];
   1.586 + 	if (argc >= 3)
   1.587 + 		port = argv[2];
   1.588 +-	if ((vnc_fd = vnc_connect(host, port)) == -1) {
   1.589 +-		fprintf(stderr, "could not connect!\n");
   1.590 ++	if ((vnc_fd = vnc_connect(host, port)) < 0) {
   1.591 ++		fprintf(stderr, "could not connect! %s %s : %d\n",
   1.592 ++			host,port,vnc_fd);
   1.593 + 		return 1;
   1.594 + 	}
   1.595 +-	if (vnc_init(vnc_fd) == -1) {
   1.596 +-		fprintf(stderr, "vnc init failed!\n");
   1.597 +-		return 1;
   1.598 ++	status = vnc_init(vnc_fd);
   1.599 ++	if (status < 0) {
   1.600 ++		fprintf(stderr, "vnc init failed! %d\n", status);
   1.601 ++		return 2;
   1.602 + 	}
   1.603 + 	term_setup(&ti);
   1.604 + 	rat_fd = open("/dev/input/mice", O_RDONLY);
   1.605 + 
   1.606 +-	mainloop(vnc_fd, 0, rat_fd);
   1.607 ++	status = mainloop(vnc_fd, 0, rat_fd);
   1.608 + 
   1.609 + 	term_cleanup(&ti);
   1.610 + 	vnc_free();
   1.611 + 	close(vnc_fd);
   1.612 + 	close(rat_fd);
   1.613 +-	return 0;
   1.614 ++	return 2 - status;
   1.615 + }