blob: 9e14d2fbc23b18b68a47893570b170279bdb3282 [file] [log] [blame]
adamdunkels2d015312003-07-02 21:34:00 +00001/*
2 * Copyright (c) 2001, Adam Dunkels
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Adam Dunkels.
16 * 4. The name of the author may not be used to endorse or promote
17 * products derived from this software without specific prior
18 * written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
21 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
26 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 * This file is part of the uIP TCP/IP stack.
33 *
34 * $Id: vnc-out.c,v 1.1 2003/07/02 21:34:00 adamdunkels Exp $
35 *
36 */
37
38#include "uip.h"
39#include "vnc-server.h"
40#include "vnc-out.h"
41
42#include "libconio.h"
43
44#include "ctk-vncfont.h"
45
46#include "ctk-arch.h"
47
48#include "ctk-mouse.h"
49
50#ifndef NOT_AVR
51#include <avr/pgmspace.h>
52#else
53#define memcpy_P memcpy
54#endif /* NOT_AVR */
55
56#define CHARS_WIDTH LIBCONIO_CONF_SCREEN_WIDTH
57#define CHARS_HEIGHT LIBCONIO_CONF_SCREEN_HEIGHT
58
59#define SCREEN_X 10
60#define SCREEN_Y 8
61
62#define FONT_WIDTH 6
63#define FONT_HEIGHT 8
64
65#define SCREEN_WIDTH (CHARS_WIDTH * FONT_WIDTH + 2 * SCREEN_X) /*420*/
66#define SCREEN_HEIGHT (CHARS_HEIGHT * FONT_HEIGHT + 2 * SCREEN_Y) /*300*/
67#define BORDER_COLOR 0x00
68#define TEXT_COLOR 0x38 /*0xe0*/
69#define SCREEN_COLOR 0x00 /*0xc0*/
70
71#define BGR(b,g,r) (((b) << 6) | (g) << 3 | (r))
72
73#define BGCOLOR BGR(1,0,1)
74
75static u8_t menucolor[] = {
76 BGR(0,7,7), /* Background. */
77 BGR(0,5,5), /* Anti-alias font color. */
78 BGR(0,0,0), /* Font color. */
79};
80
81
82static u8_t activemenucolor[] = {
83 BGR(3,7,7), /* Background. */
84 BGR(3,6,6), /* Anti-alias font color. */
85 BGR(0,0,0), /* Font color. */
86};
87
88
89static unsigned char backgroundcolor[] = {BGR(1,0,1)};
90
91static unsigned char wincol[] =
92 {BGR(2,5,5),BGR(2,2,2),BGR(0,1,1),BGR(1,0,0),BGR(2,0,0),BGR(2,1,1)};
93static unsigned char wincol_f[] =
94 {BGR(3,6,6),BGR(1,2,2),BGR(0,1,1),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)};
95static unsigned char wincol_d[] =
96 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0),BGR(2,0,0),BGR(3,2,2),BGR(3,4,4)};
97
98static unsigned char sepcol[] =
99 {BGR(2,5,5),BGR(2,6,6),BGR(3,6,6)};
100static unsigned char sepcol_f[] =
101 {BGR(3,6,6),BGR(3,5,5),BGR(2,5,5)};
102static unsigned char sepcol_d[] =
103 {BGR(3,7,7),BGR(1,5,7),BGR(0,0,0)};
104
105static unsigned char labcol[] =
106 {BGR(2,5,5),BGR(1,3,3),BGR(0,1,1)};
107static unsigned char labcol_f[] =
108 {BGR(3,6,6),BGR(3,5,5),BGR(0,0,0)};
109static unsigned char labcol_d[] =
110 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
111
112
113static unsigned char butcol[] =
114 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
115 BGR(2,5,5),BGR(2,5,5)};
116static unsigned char butcol_w[] =
117 {BGR(2,4,4),BGR(1,3,3),BGR(0,1,1),BGR(2,4,4),BGR(2,4,4),BGR(2,4,4),
118 BGR(2,5,5),BGR(2,5,5)};
119static unsigned char butcol_f[] =
120 {BGR(2,3,3),BGR(3,5,5),BGR(3,6,6),BGR(3,5,5),BGR(3,6,6),BGR(3,7,7),
121 BGR(3,6,6),BGR(2,5,5)};
122static unsigned char butcol_fw[] =
123 {BGR(3,7,7),BGR(3,6,6),BGR(0,0,0),BGR(1,7,7),BGR(2,7,7),BGR(3,7,7),
124 BGR(3,6,6),BGR(3,7,6)};
125static unsigned char butcol_d[] =
126 {BGR(2,3,3),BGR(2,5,5),BGR(3,6,6),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
127 BGR(3,7,7),BGR(2,5,5)};
128static unsigned char butcol_dw[] =
129 {BGR(0,0,0),BGR(2,5,5),BGR(3,7,7),BGR(1,3,4),BGR(1,5,6),BGR(2,6,7),
130 BGR(3,7,7),BGR(2,5,5)};
131
132
133static unsigned char hlcol[] =
134 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
135static unsigned char hlcol_w[] =
136 {BGR(2,5,5),BGR(1,3,3),BGR(1,0,0)};
137static unsigned char hlcol_f[] =
138 {BGR(3,6,6),BGR(3,5,5),BGR(3,0,0)};
139static unsigned char hlcol_fw[] =
140 {BGR(3,6,6),BGR(3,6,7),BGR(3,7,7)};
141static unsigned char hlcol_d[] =
142 {BGR(3,7,7),BGR(3,5,5),BGR(2,0,0)};
143static unsigned char hlcol_dw[] =
144 {BGR(3,7,7),BGR(1,5,5),BGR(0,0,0)};
145
146static unsigned char iconcol[] =
147 {BGR(0,1,1),BGR(2,3,3),BGR(2,5,5)};
148static unsigned char iconcol_w[] =
149 {BGR(0,1,1),BGR(2,5,5),BGR(3,7,7)};
150
151
152
153static u8_t *colortheme[] =
154 {
155 backgroundcolor,
156
157 /* Window colors */
158 wincol, wincol, wincol_f, wincol_f, wincol_d, wincol_d,
159
160 /* Separator colors. */
161 sepcol, sepcol, sepcol_f, sepcol_f, sepcol_d, sepcol_d,
162
163 /* Label colors. */
164 labcol, labcol, labcol_f, labcol_f, labcol_d, labcol_d,
165
166 /* Button colors. */
167 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
168
169 /* Hyperlink colors. */
170 hlcol, hlcol_w, hlcol_f, hlcol_fw, hlcol_d, hlcol_dw,
171
172 /* Textentry colors. */
173 butcol, butcol_w, butcol_f, butcol_fw, butcol_d, butcol_dw,
174
175 /* Icon colors */
176 iconcol, iconcol_w, iconcol, iconcol_w, iconcol, iconcol_w,
177
178 /* Menu colors. */
179 menucolor, activemenucolor, activemenucolor
180 };
181
182
183static int mouse_x, mouse_y, mouse_button;
184
185static u8_t screen[CHARS_WIDTH * CHARS_HEIGHT],
186 colorscreen[CHARS_WIDTH * CHARS_HEIGHT];
187
188
189#define PRINTF(x)
190
191/*-----------------------------------------------------------------------------------*/
192#define MAX_ICONS 16
193struct ctk_icon *icons[MAX_ICONS];
194
195unsigned char
196vnc_out_add_icon(struct ctk_icon *icon)
197{
198 u8_t i;
199 signed int empty;
200
201 empty = -1;
202 for(i = 0; i < MAX_ICONS; ++i) {
203 if(icon == icons[i]) {
204 return i;
205 }
206 if(icons[i] == NULL && empty < 0){
207 empty = i;
208 }
209 }
210
211 if(empty == -1) {
212 empty = 0;
213 }
214 icons[empty] = icon;
215 return empty;
216}
217
218/*-----------------------------------------------------------------------------------*/
219void
220vnc_out_init(void)
221{
222 u16_t i;
223 for(i = 0; i < CHARS_WIDTH * CHARS_HEIGHT; ++i) {
224 screen[i] = 0x20;
225 }
226}
227
228void
229vnc_out_update_screen(u8_t xpos, u8_t ypos, u8_t c, u8_t color)
230{
231 screen[xpos + ypos * CHARS_WIDTH] = c;
232 colorscreen[xpos + ypos * CHARS_WIDTH] = color;
233}
234/*-----------------------------------------------------------------------------------*/
235void
236vnc_out_update_area(struct vnc_server_state *vs,
237 u8_t x, u8_t y, u8_t w, u8_t h)
238{
239 u8_t x2, y2, ax2, ay2;
240 struct vnc_server_update *a, *b;
241
242 PRINTF(("update_area_connection: should update (%d:%d) (%d:%d)\n",
243 x, y, w, h));
244
245 /* First check if we already have a full update queued. If so, there
246 is no need to put this update on the list. If there is a full
247 update, it is always the first one on the list, so there is no
248 need to go step the list in search for it. */
249
250 if(vs->updates_pending != NULL &&
251 vs->updates_pending->type == VNC_SERVER_UPDATE_FULL) {
252 PRINTF(("Update_area_connecion: full update already queued...\n"));
253 return;
254 }
255
256 again:
257
258 /* Check that we don't update the same area twice by going through
259 the list and search for an update with the same coordinates. */
260 for(a = vs->updates_pending; a != NULL; a = a->next) {
261 if(a->x == x && a->y == y &&
262 a->w == w && a->h == h) {
263 PRINTF(("Update_area_connecion: found equal area\n"));
264 return;
265 }
266 }
267
268 /* Next we check if this update covers an existing update. If so, we
269 remove the old update, expand this update so that it covers both
270 areas to be updated and run through the process again. */
271 b = NULL;
272 for(a = vs->updates_pending; a != NULL; a = a->next) {
273 x2 = x + w;
274 y2 = y + h;
275
276 ax2 = a->x + a->w;
277 ay2 = a->y + a->h;
278
279 /* Test the corners of both updates to see if they are inside the
280 other area. */
281#define INSIDE(x,y,x1,y1,x2,y2) ((x1) <= (x) && \
282 (x2) >= (x) && \
283 (y1) <= (y) && \
284 (y2) >= (y))
285 if(INSIDE(x, y, a->x, a->y, ax2, ay2) ||
286 INSIDE(x, y2, a->x, a->y, ax2, ay2) ||
287 INSIDE(x2, y2, a->x, a->y, ax2, ay2) ||
288 INSIDE(x2, y, a->x, a->y, ax2, ay2) ||
289 INSIDE(a->x, a->y, x, y, x2, y2) ||
290 INSIDE(a->x, ay2, x, y, x2, y2) ||
291 INSIDE(ax2, ay2, x, y, x2, y2) ||
292 INSIDE(ax2, a->y, x, y, x2, y2)) {
293
294 /* Remove the old update from the list. */
295 vnc_server_update_remove(vs, a);
296
297 /* Put it on the free list. */
298 vnc_server_update_free(vs, a);
299
300 PRINTF(("update_area_connection: inside (%d:%d, %d:%d)\n",
301 a->x, a->y, ax2, ay2));
302
303 /* Find the area that covers both updates. */
304#define MIN(a,b) ((a) < (b)? (a): (b))
305#define MAX(a,b) ((a) > (b)? (a): (b))
306 x = MIN(a->x, x);
307 y = MIN(a->y, y);
308 ax2 = MAX(ax2, x2);
309 ay2 = MAX(ay2, y2);
310 w = ax2 - x;
311 h = ay2 - y;
312
313 /* This should really be done by a recursive call to this
314 function: update_area_connection(vs, x, y, w, h); but because
315 some compilers might not be able to optimize away the
316 recursive call, we do it using a goto instead. */
317 PRINTF(("Update_area_connecion: trying larger area (%d:%d) (%d:%d)\n", x, y, w, h));
318 goto again;
319 }
320 if(b != NULL) {
321 b = b->next;
322 }
323 }
324
325 /* Allocate an update object by pulling it off the free list. If
326 there are no free objects, we go for a full update instead. */
327
328 /* a = vs->updates_free;*/
329 a = vnc_server_update_alloc(vs);
330 if(a == NULL) {
331 PRINTF(("Update_area_connecion: no free updates, doing full\n"));
332 /* Put all pending updates, except for one, on the free list. Use
333 the remaining update as a full update. */
334 while(vs->updates_pending != NULL) {
335 a = vs->updates_pending;
336 vnc_server_update_remove(vs, a);
337 vnc_server_update_free(vs, a);
338 }
339
340 a = vnc_server_update_alloc(vs);
341 a->type = VNC_SERVER_UPDATE_FULL;
342 vnc_server_update_add(vs, a);
343
344
345 } else {
346
347 PRINTF(("Update_area_connecion: allocated update for (%d:%d) (%d:%d)\n", x, y, w, h));
348 /* Else, we put the update object at the end of the pending
349 list. */
350 a->type = VNC_SERVER_UPDATE_PARTS;
351 a->x = x;
352 a->y = y;
353 a->w = w;
354 a->h = h;
355 vnc_server_update_add(vs, a);
356 }
357}
358/*-----------------------------------------------------------------------------------*/
359static void
360init_send_screen(struct vnc_server_state *vs)
361{
362 vs->sendmsg = SEND_SCREEN;
363 vs->x = vs->y = 0;
364 vs->x1 = vs->y1 = 0;
365 vs->x2 = vs->y2 = 0;
366 vs->w = CHARS_WIDTH;
367 vs->h = CHARS_HEIGHT;
368}
369/*-----------------------------------------------------------------------------------*/
370static void
371check_updates(struct vnc_server_state *vs)
372{
373
374 if(vs->state == VNC_RUNNING &&
375 vs->sendmsg == SEND_NONE &&
376 vs->updates_current == NULL) {
377 if(vs->updates_pending != NULL &&
378 vs->update_requested != 0) {
379 vs->update_requested = 0;
380 /* vs->updates_current = vs->updates_pending;
381 vs->updates_pending = vs->updates_pending->next;
382 vs->updates_current->next = NULL;*/
383
384 vs->updates_current = vnc_server_update_dequeue(vs);
385
386 if(vs->updates_current->type == VNC_SERVER_UPDATE_PARTS) {
387 vs->x = vs->x1 = vs->x2 = vs->updates_current->x;
388 vs->y = vs->y1 = vs->y2 = vs->updates_current->y;
389 vs->w = vs->updates_current->w;
390 vs->h = vs->updates_current->h;
391 vs->sendmsg = SEND_UPDATE;
392
393 PRINTF(("New update from (%d:%d) (%d:%d) to (%d:%d)\n",
394 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
395 vs->y + vs->h));
396 } else if(vs->updates_current->type == VNC_SERVER_UPDATE_FULL) {
397 init_send_screen(vs);
398 PRINTF(("New full update\n"));
399 }
400 }
401 }
402}
403/*-----------------------------------------------------------------------------------*/
404static u8_t tmp[FONT_WIDTH * FONT_HEIGHT];
405static void
406makechar(char *ptr, u8_t x, u8_t y)
407{
408 u8_t i, *tmpptr;
409 u8_t *colorscheme;
410 unsigned char *bitmap;
411 u8_t b, b2;
412 u8_t xmove, ymove;
413 unsigned char c, color;
414
415 color = colorscreen[x + y * CHARS_WIDTH];
416 c = screen[x + y * CHARS_WIDTH];
417
418 colorscheme = colortheme[color];
419
420 /* First check if the character is a special icon character. These
421 are to be interpreted in a special manner: the first character of
422 the icon (the top left corner) has the highest bit set, but not
423 but 6. All other characters have bit 6 set, and also count the
424 number of positions away from the top left corner. Only the top
425 left corner contains enough information to identify the icon, all
426 other chars only contain the number of steps to reach the
427 identifying icon. */
428 if((c & 0x80) != 0) {
429 xmove = c & 0x0f;
430 ymove = (c & 0x30) >> 4;
431
432 c = colorscreen[x + y * CHARS_WIDTH];
433 bitmap = icons[c & 0x3f]->bitmap + ymove * 8*3;
434
435 colorscheme = colortheme[VNC_OUT_ICONCOLOR + (c >> 6)];
436 switch(xmove) {
437 case 0:
438 for(i = 0; i < FONT_HEIGHT; ++i) {
439 b = bitmap[i];
440 *ptr++ = colorscheme[(b >> 7) & 0x01];
441 *ptr++ = colorscheme[(b >> 6) & 0x01];
442 *ptr++ = colorscheme[(b >> 5) & 0x01];
443 *ptr++ = colorscheme[(b >> 4) & 0x01];
444 *ptr++ = colorscheme[(b >> 3) & 0x01];
445 *ptr++ = colorscheme[(b >> 2) & 0x01];
446 }
447 break;
448 case 1:
449 for(i = 0; i < FONT_HEIGHT; ++i) {
450 b = bitmap[i];
451 b2 = bitmap[i + 8];
452 *ptr++ = colorscheme[(b >> 1) & 0x01];
453 *ptr++ = colorscheme[(b >> 0) & 0x01];
454 *ptr++ = colorscheme[(b2 >> 7) & 0x01];
455 *ptr++ = colorscheme[(b2 >> 6) & 0x01];
456 *ptr++ = colorscheme[(b2 >> 5) & 0x01];
457 *ptr++ = colorscheme[(b2 >> 4) & 0x01];
458 }
459 break;
460 case 2:
461 for(i = 0; i < FONT_HEIGHT; ++i) {
462 b = bitmap[i+8];
463 b2 = bitmap[i+16];
464 *ptr++ = colorscheme[(b >> 3) & 0x01];
465 *ptr++ = colorscheme[(b >> 2) & 0x01];
466 *ptr++ = colorscheme[(b >> 1) & 0x01];
467 *ptr++ = colorscheme[(b >> 0) & 0x01];
468 *ptr++ = colorscheme[(b2 >> 7) & 0x01];
469 *ptr++ = colorscheme[(b2 >> 6) & 0x01];
470 }
471 break;
472 case 3:
473 for(i = 0; i < FONT_HEIGHT; ++i) {
474 b = bitmap[i+16];
475 *ptr++ = colorscheme[(b >> 5) & 0x01];
476 *ptr++ = colorscheme[(b >> 4) & 0x01];
477 *ptr++ = colorscheme[(b >> 3) & 0x01];
478 *ptr++ = colorscheme[(b >> 2) & 0x01];
479 *ptr++ = colorscheme[(b >> 1) & 0x01];
480 *ptr++ = colorscheme[(b >> 0) & 0x01];
481 }
482 break;
483 }
484 } else {
485 memcpy_P(tmp, &ctk_vncfont[c * (FONT_WIDTH * FONT_HEIGHT)],
486 FONT_WIDTH * FONT_HEIGHT);
487
488 tmpptr = tmp;
489
490
491 for(i = 0; i < FONT_HEIGHT * FONT_WIDTH; ++i) {
492 *ptr++ = colorscheme[*tmpptr++];
493 }
494 }
495}
496/*-----------------------------------------------------------------------------------*/
497void
498vnc_out_new(struct vnc_server_state *vs)
499{
500 u8_t i;
501
502 vs->width = SCREEN_WIDTH;
503 vs->height = SCREEN_HEIGHT;
504 vs->x = vs->y = vs->x1 = vs->y1 = vs->x2 = vs->y2 = 0;
505 vs->w = CHARS_WIDTH;
506 vs->h = CHARS_HEIGHT;
507
508 /* Initialize the linked list of updates. */
509 for(i = 0; i < VNC_SERVER_MAX_UPDATES - 1; ++i) {
510 vs->updates_pool[i].next = &vs->updates_pool[i + 1];
511 }
512 vs->updates_pool[VNC_SERVER_MAX_UPDATES].next = NULL;
513
514 vs->updates_free = &vs->updates_pool[0];
515 vs->updates_pending = vs->updates_current = NULL;
516}
517/*-----------------------------------------------------------------------------------*/
518void
519vnc_out_send_blank(struct vnc_server_state *vs)
520{
521 struct rfb_fb_update *umsg;
522 u8_t *ptr;
523 u16_t len;
524 u8_t msglen;
525
526 vs->x = vs->y = 0;
527 vs->x2 = vs->y2 = 0;
528
529 umsg = (struct rfb_fb_update *)uip_appdata;
530
531 umsg->type = RFB_FB_UPDATE;
532 umsg->rects = HTONS(2);
533
534 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
535 len = sizeof(struct rfb_fb_update);
536
537 msglen = vnc_server_draw_rect(ptr, 0, 0,
538 HTONS(SCREEN_WIDTH),
539 HTONS(SCREEN_HEIGHT),
540 BORDER_COLOR);
541
542
543 ptr += msglen;
544 len += msglen;
545
546 msglen = vnc_server_draw_rect(ptr,
547 HTONS(SCREEN_X), HTONS(SCREEN_Y),
548 HTONS(SCREEN_WIDTH - SCREEN_X * 2),
549 HTONS(SCREEN_HEIGHT - SCREEN_Y * 2),
550 SCREEN_COLOR);
551
552 uip_send(uip_appdata, len + msglen);
553
554 vs->sendmsg = SENT_BLANK;
555}
556/*-----------------------------------------------------------------------------------*/
557void
558vnc_out_send_screen(struct vnc_server_state *vs)
559{
560 vnc_out_send_update(vs);
561}
562/*-----------------------------------------------------------------------------------*/
563
564void
565vnc_out_send_update(struct vnc_server_state *vs)
566{
567 u8_t x, y, x0;
568 u8_t msglen;
569 u16_t len, n;
570 u8_t *ptr;
571 struct rfb_fb_update *umsg;
572 struct rfb_fb_update_rect_hdr *recthdr;
573 struct rfb_rre_hdr *rrehdr;
574 u8_t c, color, lastcolor;
575 u8_t numblanks;
576
577 /* First, check if we need to feed the update function with a new
578 pending update. */
579 check_updates(vs);
580
581 /* PRINTF(("Sending Update from (%d:%d) (%d:%d) to (%d:%d)\n",
582 vs->x, vs->y, vs->x1, vs->y1, vs->x + vs->w,
583 vs->y + vs->h));*/
584
585 umsg = (struct rfb_fb_update *)uip_appdata;
586
587 umsg->type = RFB_FB_UPDATE;
588
589 x0 = vs->x1;
590 n = 0;
591 msglen = 0;
592 ptr = (u8_t *)umsg + sizeof(struct rfb_fb_update);
593 len = sizeof(struct rfb_fb_update);
594
595 /* Loop over all characters that are covered by this update. */
596 for(y = vs->y1; y < vs->y + vs->h; ++y) {
597 for(x = x0; x < vs->x + vs->w; ++x) {
598
599
600 /* First check if there are any blank space characters, and if
601 so, find out how many of them there are in a row. Instead of
602 sending the individual space characters as raw bitmaps, we
603 can send the entire string of blanks as a single color
604 rectangle instead. */
605
606 c = screen[x + y * CHARS_WIDTH];
607 numblanks = 0;
608 lastcolor = color = colorscreen[x + y * CHARS_WIDTH];
609
610 /* If the character is a blank, we continue reading characters
611 until we find one that has a different color, or one that is
612 not a blank. We must keep within the update rectangle, so we
613 make sure that the "x" variable does not increase beyond the
614 edge. The "numblanks" variable is used to keep track of how
615 many blank characters we have found. */
616 while(lastcolor == color &&
617 c == 0x20 &&
618 x < vs->x + vs->w) {
619 ++numblanks;
620
621
622 ++x;
623 lastcolor = color;
624 color = colorscreen[x + y * CHARS_WIDTH];
625 c = screen[x + y * CHARS_WIDTH];
626 }
627
628 if(numblanks > 0) {
629
630 /* PRINTF(("Found %d blanks (%d:%d -> %d:%d)\n",
631 numblanks, x - numblanks, y, x, y));*/
632
633 /* There were one or more blank characters, so we send out a
634 single color rectangle with the right width. But first we
635 make sure that there is enough space in the current TCP
636 segment to put the rectangle. If there isn't we have to
637 backtrack the "x" variable to where we found the first
638 blank character so that the next TCP segment will be able
639 to update this area instead. */
640
641 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
642 sizeof(struct rfb_rre_hdr);
643
644 if(msglen >= uip_mss() - len) {
645 /* PRINTF(("Not enouch space for blanks (%d, left %d)\n",
646 msglen, uip_mss() - len));*/
647 /* There is not enough space in the segment, so we remember
648 where we were ... */
649 vs->x2 = x - numblanks;
650 vs->y2 = y;
651
652 /* ... and we break out of the loop. */
653 goto loopend;
654 }
655
656 /* We construct a rectangle with the right width and color. */
657 recthdr = (struct rfb_fb_update_rect_hdr *)ptr;
658 rrehdr = (struct rfb_rre_hdr *)(ptr +
659 sizeof(struct rfb_fb_update_rect_hdr));
660
661 /* PRINTF(("Blankign (%d:%d) to (%d:%d)\n",
662 (x - numblanks) * FONT_WIDTH,
663 y * FONT_HEIGHT,
664 FONT_WIDTH * numblanks,
665 FONT_HEIGHT));*/
666 recthdr->rect.x = htons(SCREEN_X + (x - numblanks) *
667 FONT_WIDTH);
668 recthdr->rect.y = htons(SCREEN_Y + y * FONT_HEIGHT);
669 recthdr->rect.w = htons(FONT_WIDTH * numblanks);
670 recthdr->rect.h = HTONS(FONT_HEIGHT);
671 recthdr->encoding[0] =
672 recthdr->encoding[1] =
673 recthdr->encoding[2] = 0;
674 recthdr->encoding[3] = RFB_ENC_RRE;
675
676 rrehdr->subrects[0] =
677 rrehdr->subrects[1] = 0;
678 rrehdr->bgpixel = colortheme[lastcolor][0];
679
680 --x;
681 } else {
682
683 /* So there were no blank characters. */
684
685 /* PRINTF(("An char at (%d:%d)\n", x, y));*/
686 /* First we must make sure that there is enough space in the
687 outgoing TCP segment. */
688
689 msglen = sizeof(struct rfb_fb_update_rect_hdr) +
690 FONT_HEIGHT * FONT_WIDTH;
691 if(msglen >= uip_mss() - len) {
692 /* PRINTF(("Not enouch space for char (%d, left %d)\n",
693 msglen, uip_mss() - len));*/
694
695 /* There is not enough space in the segment, so we remember
696 where we were ... */
697 vs->x2 = x;
698 vs->y2 = y;
699
700 /* ... and we break out of the loop. */
701 goto loopend;
702 }
703
704 /* PRINTF(("ptr %p\n",ptr);*/
705 recthdr = (struct rfb_fb_update_rect_hdr *)ptr;
706
707 recthdr->rect.x = htons(SCREEN_X + x * FONT_WIDTH);
708 recthdr->rect.y = htons(SCREEN_Y + y * FONT_HEIGHT);
709 recthdr->rect.w = HTONS(FONT_WIDTH);
710 recthdr->rect.h = HTONS(FONT_HEIGHT);
711 recthdr->encoding[0] =
712 recthdr->encoding[1] =
713 recthdr->encoding[2] = 0;
714 recthdr->encoding[3] = RFB_ENC_RAW;
715
716 makechar((u8_t *)recthdr +
717 sizeof(struct rfb_fb_update_rect_hdr),
718 x, y);
719#if 0
720 c,
721 /* &ctk_vncfont[c * (FONT_WIDTH * FONT_HEIGHT)]*/
722 color);
723#endif /* 0 */
724 /* PRINTF(("Msglen %d (%d:%d)\n", msglen, x, y);*/
725 }
726 len += msglen;
727 ptr += msglen;
728 ++n;
729 }
730 x0 = vs->x;
731 }
732
733 loopend:
734
735 umsg->rects = htons(n);
736
737 if(y == vs->y + vs->h && x == vs->x + vs->w) {
738 vs->x2 = vs->y2 = 0;
739 }
740
741 if(n > 0) {
742 /* printf("Sending %d rects, %d bytes (%p, %p, %p)\n", n, len,
743 uip_appdata, umsg, ptr);*/
744 uip_send(uip_appdata, len);
745 }
746
747}
748/*-----------------------------------------------------------------------------------*/
749#define NUMKEYS 100
750static char keys[NUMKEYS];
751static int firstkey, lastkey;
752
753
754char
755vnc_out_keyavail(void)
756{
757 return firstkey != lastkey;
758}
759
760char
761vnc_out_getkey(void)
762{
763 char key;
764 key = keys[firstkey];
765
766 if(firstkey != lastkey) {
767 ++firstkey;
768 if(firstkey >= NUMKEYS) {
769 firstkey = 0;
770 }
771 }
772
773 return key;
774}
775
776void
777vnc_out_key_event(struct vnc_server_state *vs)
778{
779 struct rfb_key_event *ev;
780
781 ev = (struct rfb_key_event *)uip_appdata;
782
783 if(ev->down != 0) {
784 if(vs->sendmsg == SEND_NONE) {
785 vs->sendmsg = SEND_UPDATE;
786 }
787
788
789 if(ev->key[2] == 0 ||
790 (ev->key[2] == 0xff &&
791 (ev->key[3] == CH_HOME ||
792 ev->key[3] == CH_TAB ||
793 ev->key[3] == CH_ESC ||
794 ev->key[3] == CH_DEL ||
795 ev->key[3] == CH_ENTER ||
796 ev->key[3] == CH_CURS_LEFT ||
797 ev->key[3] == CH_CURS_UP ||
798 ev->key[3] == CH_CURS_RIGHT ||
799 ev->key[3] == CH_CURS_DOWN))) {
800
801 keys[lastkey] = ev->key[3];
802 ++lastkey;
803 if(lastkey >= NUMKEYS) {
804 lastkey = 0;
805 }
806 }
807 }
808
809 check_updates(vs);
810}
811/*-----------------------------------------------------------------------------------*/
812void
813vnc_out_pointer_event(struct vnc_server_state *vs)
814{
815 struct rfb_pointer_event *ev;
816 u16_t evx, evy;
817
818 ev = (struct rfb_pointer_event *)uip_appdata;
819
820 evx = htons(ev->x);
821 evy = htons(ev->y);
822
823 if(evx > SCREEN_X && evx < SCREEN_WIDTH - 2 * SCREEN_X &&
824 evy > SCREEN_Y && evy < SCREEN_HEIGHT - 2 * SCREEN_Y) {
825
826 mouse_button = ev->buttonmask & RFB_BUTTON_MASK1;
827
828 mouse_x = evx - SCREEN_X;
829 mouse_y = evy - SCREEN_Y;
830
831 check_updates(vs);
832 }
833}
834/*-----------------------------------------------------------------------------------*/
835void
836vnc_out_acked(struct vnc_server_state *vs)
837{
838 if(vs->state != VNC_RUNNING) {
839 return;
840 }
841 if(vs->sendmsg == SENT_BLANK) {
842 init_send_screen(vs);
843 } else if(vs->sendmsg == SEND_BLANK) {
844 /* Do nothing until sendmsg == SENT_BLANK. */
845 } else if(vs->sendmsg == SEND_SCREEN) {
846 /* When the screen has been fully drawn, ->x2 and ->y2 are both
847 set to 0 to indicate this.*/
848 if(vs->x2 == 0 && vs->y2 == 0) {
849 vs->sendmsg = SEND_NONE;
850
851 /* If there was an updaterequest for the entire screen, we can
852 clear that flag now. */
853 if(vs->updates_current != NULL) {
854 vnc_server_update_free(vs, vs->updates_current);
855 vs->updates_current = NULL;
856 }
857 check_updates(vs);
858 } else {
859 vs->x1 = vs->x2;
860 vs->y1 = vs->y2;
861 }
862
863 } else if(vs->sendmsg == SEND_UPDATE) {
864 if(vs->x2 == 0 && vs->y2 == 0) {
865 /* So, we have updated the area that we needed. We now check if
866 there have been any recent full screen update requests. If
867 so, we need to go to the SEND_SCREEN state. Else, we see if
868 there were more areas that needed to be updated and if so,
869 we'll continue with those. */
870
871 vs->sendmsg = SEND_NONE;
872
873 if(vs->updates_current != NULL) {
874 vnc_server_update_free(vs, vs->updates_current);
875 vs->updates_current = NULL;
876
877 }
878 check_updates(vs);
879#if 0
880 if(vs->updaterequest == VNC_SERVER_UPDATE_FULL) {
881 check_updates(vs);
882 } else {
883 vs->updatesptr2 = (vs->updatesptr2 + 1) %
884 VNC_SERVER_MAX_UPDATES;
885
886 /* If there are no more updates to do, we'll go back to the
887 SEND_NONE state. */
888 if(vs->updatesptr2 == vs->updatesptr) {
889 vs->updatetype = VNC_SERVER_UPDATE_NONE;
890 } else {
891 /* Otherwise, we continue to update the next area. */
892 vs->updaterequest = VNC_SERVER_UPDATE_PARTS;
893 check_updates(vs);
894 }
895 }
896#endif /* 0 */
897 } else {
898 vs->x1 = vs->x2;
899 vs->y1 = vs->y2;
900 }
901 } else {
902 vs->sendmsg = SEND_NONE;
903 }
904}
905/*-----------------------------------------------------------------------------------*/
906void
907vnc_out_poll(struct vnc_server_state *vs)
908{
909 /* PRINTF(("vs->state %d, sendmsg %d, updatetype %d, updatereq %d\n",
910 vs->state, vs->sendmsg, vs->updatetype, vs->updaterequest);*/
911
912 if(vs->state == VNC_RUNNING &&
913 vs->sendmsg == SEND_NONE) {
914 check_updates(vs);
915 vnc_server_send_data(vs);
916 }
917}
918/*-----------------------------------------------------------------------------------*/
919void
920ctk_mouse_init(void)
921{
922
923}
924/*-----------------------------------------------------------------------------------*/
925unsigned short
926ctk_mouse_x(void)
927{
928 return mouse_x;
929}
930/*-----------------------------------------------------------------------------------*/
931unsigned short
932ctk_mouse_y(void)
933{
934 return mouse_y;
935}
936/*-----------------------------------------------------------------------------------*/
937unsigned char
938ctk_mouse_xtoc(unsigned short x)
939{
940 return x / FONT_WIDTH;
941}
942/*-----------------------------------------------------------------------------------*/
943unsigned char
944ctk_mouse_ytoc(unsigned short y)
945{
946 return y / FONT_HEIGHT;
947}
948/*-----------------------------------------------------------------------------------*/
949unsigned char
950ctk_mouse_button(void)
951{
952 return mouse_button;
953}
954/*-----------------------------------------------------------------------------------*/
955void
956ctk_mouse_hide(void)
957{
958}
959/*-----------------------------------------------------------------------------------*/
960void
961ctk_mouse_show(void)
962{
963}
964/*-----------------------------------------------------------------------------------*/